Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python sending email too slow

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')
like image 957
s5s Avatar asked Jun 13 '26 13:06

s5s


2 Answers

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) 

Output

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())
like image 72
jfs Avatar answered Jun 15 '26 03:06

jfs


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.

like image 33
Mark Lavin Avatar answered Jun 15 '26 01:06

Mark Lavin