xpanta
xpanta

Reputation: 8418

python. Can I check if SMTP Server is disconnected (so I can connect again?)

I am using smtplib and I am sending notification emails from my application. However I noticed that sometimes (especially when there is a lot of idle time between mail sending) I get a SMTPServerDisconnected error.

I guess there are 2 solutions for this (know none of them, though)

  1. Increase idle time between sending mails
  2. reconnect when connection is down.

I think 2nd solution seems more elegant. But how can I do that?

edit: I am adding the code

from smtplib import SMTP
smtp = SMTP()
smtp.connect('smtp.server.com')
smtp.login('username','password')

def notifyUser():
    smtp.sendmail(from_email, to_email, msg.as_string())

Upvotes: 13

Views: 24034

Answers (2)

Ethan
Ethan

Reputation: 4995

Yes, you can check if the connection is open. To do this, issue a NOOP command and test for status == 250. If not, then open the connection before sending out your mail.

def test_conn_open(conn):
    try:
        status = conn.noop()[0]
    except:  # smtplib.SMTPServerDisconnected
        status = -1
    return True if status == 250 else False

def send_email(conn, from_email, to_email, msg):
   if not test_conn_open(conn):
       conn = create_conn()
   conn.sendmail(from_email, to_email, msg.as_string())
   return conn    # as you want are trying to reuse it.

Note that you are doing this as opening a connection, say with gmail, consumes time, like 2-3 secs. Subsequently, to optimize on sending multiple emails that you may have at hand, then you should also follow Pedro's response (last part).

Upvotes: 17

Pedro Romano
Pedro Romano

Reputation: 11203

If your use case is sending a single message at a time, the solution that seems most correct to me, would be to create a new SMTP session for each message:

from smtplib import SMTP

smtp = SMTP('smtp.server.com')

def notifyUser(smtp, smtp_user, smtp_password, from_email, to_email, msg):
    smtp.login(smtp_user, smtp_password)
    smtp.sendmail(from_email, to_email, msg.as_string())
    smtp.quit()

If your SMTP server doesn't required that you authenticate yourself (a common case), this can be further simplified to:

from smtplib import SMTP

smtp = SMTP('smtp.server.com')

def notifyUser(smtp, from_email, to_email, msg):
    smtp.sendmail(from_email, to_email, msg.as_string())
    smtp.quit()

If it is common to have more than one message to send at once, and you want to optimise this case by reusing the same SMTP session for the group of messages (can be simplified as above if you don't need to login to the SMTP server):

from smtplib import SMTP

smtp = SMTP('smtp.server.com')

def notifyUsers(smtp, smtp_user, smtp_password, from_to_msgs):
    """
    :param from_to_msgs: iterable of tuples with `(from_email, to_email, msg)`
    """
    smtp.login(smtp_user, smtp_password)
    for from_email, to_email, msg in from_to_msgs:
        smtp.sendmail(from_email, to_email, msg.as_string())
    smtp.quit()

Upvotes: 9

Related Questions