I have the script below which I'm using to send say 10 messages myself<->myself. However, I've noticed that Python really takes a while to do that. Last year I needed a system to send about 200 emails with attachments and text and I implemented it with msmtp + bash. As far as I remember it was much faster.
Moving the while loop inside (around the smtp_serv.sendmail(sender, recepient, msg) function yields similar results).
Am I doing something wrong? Surely it can't be slower than bash + msmtp (and I'm only sending a 'hi' message, no attachments).
#! /usr/bin/python3.1
def sendmail(recepient, msg):
import smtplib
# Parameters
sender = '[email protected]'
password = 'password'
smtpStr = 'smtp.gmail.com'
smtpPort = 587
# /Parameters
smtp_serv = smtplib.SMTP(smtpStr, smtpPort)
smtp_serv.ehlo_or_helo_if_needed()
smtp_serv.starttls()
smtp_serv.ehlo()
recepientExists = smtp_serv.verify(recepient)
if recepientExists[0] == 250:
smtp_serv.login(sender, password)
try:
smtp_serv.sendmail(sender, recepient, msg)
except smtplib.SMTPException:
print(recepientExists[1])
else:
print('Error', recepientExists[0], ':', recepientExists[1])
smtp_serv.quit()
for in in range(10):
sendmail('[email protected]', 'hi')
In this script it takes five times more time to setup SMTP connection (5 seconds) than to send a e-mail (1 second) so it could make sense to setup a single connection and send several e-mails instead of creating the connection each time:
#!/usr/bin/env python3
import smtplib
from contextlib import contextmanager
from datetime import datetime
from email.mime.text import MIMEText
from netrc import netrc
from timeit import default_timer as timer
@contextmanager
def logined(sender, password, smtp_host='smtp.gmail.com', smtp_port=587):
start = timer(); smtp_serv = smtplib.SMTP(smtp_host, smtp_port, timeout=10)
try: # make smtp server and login
smtp_serv.ehlo_or_helo_if_needed()
smtp_serv.starttls()
smtp_serv.ehlo()
print('smtp setup took (%.2f seconds passed)' % (timer()-start,))
start = timer(); smtp_serv.login(sender, password)
print('login took %.2f seconds' % (timer()-start,))
start = timer(); yield smtp_serv
finally:
print('Operations with smtp_serv took %.2f seconds' % (timer()-start,))
start = timer(); smtp_serv.quit()
print('Quiting took %.2f seconds' % (timer()-start,))
smtp_host = 'smtp.gmail.com'
login, _, password = netrc().authenticators(smtp_host)
with logined(login, password, smtp_host) as smtp_serv:
for i in range(10):
msg = MIMEText('#%d timestamp %s' % (i, datetime.utcnow()))
msg['Subject'] = 'test #%d' % i
msg['From'] = login
msg['To'] = login
smtp_serv.send_message(msg)
smtp setup took (5.43 seconds passed)
login took 0.40 seconds
Operations with smtp_serv took 9.84 seconds
Quiting took 0.05 seconds
If your Python version doesn't have .send_message() then you could use:
smtp_serv.sendmail(from, to, msg.as_string())
You are opening the connection to the SMTP server and then closing it for each email. It would be more efficient to keep the connection open while sending all of the emails.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With