Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

python

smtplib

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())
like image 737
xpanta Avatar asked Sep 23 '12 13:09

xpanta


People also ask

How do I know if SMTP is open?

Type telnet MAILSERVER 25 (replace MAILSERVER with your mail server (SMTP) which may be something like server.domain.com or mail.yourdomain.com). Press Enter. If that port is blocked, you will receive a connection error.


2 Answers

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()
like image 165
Pedro Romano Avatar answered Sep 27 '22 23:09

Pedro Romano


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).

like image 37
Ethan Avatar answered Sep 28 '22 00:09

Ethan