Email Issue

I’m trying to send myself email from my own Linux machine, via SMPT. I’ve written the following Python program:

#!/usr/bin/env python3

# Import smtplib for the actual sending function
import smtplib

# Import the email modules we’ll need
from email.mime.text import MIMEText

# Open a plain text file for reading. For this example, assume that
# the text file contains only ASCII characters.
with open(“test.txt”) as fp:
# Create a text/plain message
msg = MIMEText(fp.read())

# me == the sender’s email address
# you == the recipient’s email address
msg[‘Subject’] = “Test”
msg[‘From’] = “simberg@interglobal.org”
msg[‘To’] = “simberg@interglobal.org”

# Send the message via our own SMTP server.
s = smtplib.SMTP(‘localhost’)
print(“s has been opened”)
s.send_message(msg)
print(“after send_message”)
s.quit()
print(“End script”)

It runs with no errors, prints the statements to the terminal, but no email appears. How do I diagnose this?

[Update a while later]

Thanks for the help in comments. Still haven’t solved it, but the need for the application that I needed it for has gone away. Nonetheless, it would be good in general to know how to email from a Python script.

24 thoughts on “Email Issue”

  1. Wild guess: Put in a 5 sec delay after the send(). Maybe there’s a queue that gets clobbered by the quit().

  2. Also check which port your SMTP server is using. That is the optional 2nd argument smtplib.SMTP() it defaults to 25.

    smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]]

    Googling the phrase smtp ports yielded this nugget:

    SMTP by default uses TCP port 25. The protocol for mail submission is the same, but uses port 587. SMTP connections secured by SSL, known as SMTPS, default to port 465 (nonstandard, but sometimes used for legacy reasons).

  3. its entirely possible you have successfully sent mail to your mailserver local to your device, but now, it needs to send it to the MX of interglobal.org, and if that’s not your laptop, its probably queued up inside your SMTP mailer until it learns hot to send mail out. I have no idea what sort of local mailer you have, so look inside it’s logs for delivery status. The mail could be sitting there in the queue, unable to deliver. Or, it is working just fine, and the upstream SMTP server at interglobal.org is looking at your to and from and thinking “hah, spammer”.

    1. I’m talking to the admin for interglobal.org, and he’s not seeing anything in his logs. I’ve no idea where the logs are for smtp.

      I often send email to myself as a means of file backup or move, so I don’t think that’s the problem.

  4. Turn on smtplib lame debugprint support

    s = smtplib.SMTP()
    s.debuglevel = 10
    s.connect(‘localhost’)

      1. That should be just copypaste error .. i.e. the .py file UTF8/ascii encoding or something. Zap any suspect marks and maybe change all quote marks to double quotes “. The code itself is fine.

        Longer modified segment :

        # Send the message via our own SMTP server.
        s = smtplib.SMTP()
        print(“s has been opened”)
        s.debuglevel = 10
        s.connect(“localhost”)
        print(“s has been connected”)
        s.send_message(msg)

        1. Yeah, it pasted as a backtick. Here’s the output now:

          connect: (‘localhost’, 25)
          connect: to (‘localhost’, 25) None
          reply: b’220 new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 13:37:28 -0700\r\n’
          reply: retcode (220); Msg: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 13:37:28 -0700′
          connect: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 13:37:28 -0700′
          s has been opened
          after send_message
          End script
          You have new mail in /var/spool/mail/simberg

          1. Doesnt look like its actually writing anything to the server connection, its supposed to dump out SMTP protocol commands like EHLO etc. Not sure why – could be, could be a TLS connection is required maybe. call:
            s.starttls()

            or call
            s.ehlo()
            right after s.connect()

            You can run a simpler test with :

            python -m smtplib

            That will just run smptplib default demo sendmail code , which is at the end here :

            https://github.com/enthought/Python-2.7.3/blob/master/Lib/smtplib.py

            Generally, python’s default smtplib in python is not too straightforward, i can never figure out whats wrong with it unless i step through the code in a debugger – or i use a bit more robust library/service

            You can try grabbing a bit more fully developed script like this and modify accordingly too :
            https://gist.github.com/dbieber/5146518

          2. From: simberg@interglobal.org
            To: simberg@interglobal.org
            Enter message, end with ^D:
            testing.

            Message length is 10
            send: ‘ehlo new-host-5.home\r\n’
            reply: ‘250-new-host-5.home Hello localhost.localdomain [127.0.0.1], pleased to meet you\r\n’
            reply: ‘250-ENHANCEDSTATUSCODES\r\n’
            reply: ‘250-PIPELINING\r\n’
            reply: ‘250-8BITMIME\r\n’
            reply: ‘250-SIZE\r\n’
            reply: ‘250-DSN\r\n’
            reply: ‘250-ETRN\r\n’
            reply: ‘250-AUTH GSSAPI DIGEST-MD5 CRAM-MD5\r\n’
            reply: ‘250-DELIVERBY\r\n’
            reply: ‘250 HELP\r\n’
            reply: retcode (250); Msg: new-host-5.home Hello localhost.localdomain [127.0.0.1], pleased to meet you
            ENHANCEDSTATUSCODES
            PIPELINING
            8BITMIME
            SIZE
            DSN
            ETRN
            AUTH GSSAPI DIGEST-MD5 CRAM-MD5
            DELIVERBY
            HELP
            send: ‘mail FROM: size=10\r\n’
            reply: ‘250 2.1.0
            … Sender ok\r\n’
            reply: retcode (250); Msg: 2.1.0
            … Sender ok
            send: ‘rcpt TO:
            \r\n’
            reply: ‘250 2.1.5
            … Recipient ok\r\n’
            reply: retcode (250); Msg: 2.1.5
            … Recipient ok
            send: ‘data\r\n’
            reply: ‘354 Enter mail, end with “.” on a line by itself\r\n’
            reply: retcode (354); Msg: Enter mail, end with “.” on a line by itself
            data: (354, ‘Enter mail, end with “.” on a line by itself’)
            send: ‘testing.\r\n\r\n.\r\n’
            reply: ‘250 2.0.0 u3FL6YFa011025 Message accepted for delivery\r\n’
            reply: retcode (250); Msg: 2.0.0 u3FL6YFa011025 Message accepted for delivery
            data: (250, ‘2.0.0 u3FL6YFa011025 Message accepted for delivery’)
            send: ‘quit\r\n’
            reply: ‘221 2.0.0 new-host-5.home closing connection\r\n’
            reply: retcode (221); Msg: 2.0.0 new-host-5.home closing connection

          3. Ah, another tiny detail is to print out what the send_message() method spits back. like this

            result = s.send_message(msg)
            print(“after send_message”)
            print(result)

  5. Doh, i think you have a zero-length ‘TO’ address list. SMTPlist expects the input parameters on to field to be a list ( or a tuple ), not a single value
    So if you change:

    msg[‘To’] = “simberg@interglobal.org”

    to
    msg[‘To’] = [“simberg@interglobal.org”] # makes a 1-element list
    or
    msg[‘To’] = (“simberg@interglobal.org”,) # makes a tuple

    It just might work

    1. With square brackets:

      connect: (‘localhost’, 25)
      connect: to (‘localhost’, 25) None
      reply: b’220 new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 14:25:33 -0700\r\n’
      reply: retcode (220); Msg: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 14:25:33 -0700′
      connect: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 14:25:33 -0700′
      send: ‘ehlo new-host-5.home\r\n’
      reply: b’250-new-host-5.home Hello localhost.localdomain [127.0.0.1], pleased to meet you\r\n’
      reply: b’250-ENHANCEDSTATUSCODES\r\n’
      reply: b’250-PIPELINING\r\n’
      reply: b’250-8BITMIME\r\n’
      reply: b’250-SIZE\r\n’
      reply: b’250-DSN\r\n’
      reply: b’250-ETRN\r\n’
      reply: b’250-AUTH GSSAPI DIGEST-MD5 CRAM-MD5\r\n’
      reply: b’250-DELIVERBY\r\n’
      reply: b’250 HELP\r\n’
      reply: retcode (250); Msg: b’new-host-5.home Hello localhost.localdomain [127.0.0.1], pleased to meet you\nENHANCEDSTATUSCODES\nPIPELINING\n8BITMIME\nSIZE\nDSN\nETRN\nAUTH GSSAPI DIGEST-MD5 CRAM-MD5\nDELIVERBY\nHELP’
      send: ‘mail FROM: size=192\r\n’
      reply: b’250 2.1.0
      … Sender ok\r\n’
      reply: retcode (250); Msg: b’2.1.0
      … Sender ok’
      send: ‘rcpt TO:
      \r\n’
      reply: b’250 2.1.5
      … Recipient ok\r\n’
      reply: retcode (250); Msg: b’2.1.5
      … Recipient ok’
      send: ‘data\r\n’
      reply: b’354 Enter mail, end with “.” on a line by itself\r\n’
      reply: retcode (354); Msg: b’Enter mail, end with “.” on a line by itself’
      data: (354, b’Enter mail, end with “.” on a line by itself’)
      send: b’Content-Type: text/plain; charset=”us-ascii”\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nSubject: Test\r\nFrom: simberg@interglobal.org\r\nTo: simberg@interglobal.org\r\n\r\nThis is a test.\r\n.\r\n’
      reply: b’250 2.0.0 u3FLPXbD011626 Message accepted for delivery\r\n’
      reply: retcode (250); Msg: b’2.0.0 u3FLPXbD011626 Message accepted for delivery’
      data: (250, b’2.0.0 u3FLPXbD011626 Message accepted for delivery’)
      after send_message
      {}
      s has been opened
      after send_message
      End script
      [simberg@new-host-5 Python]$ ./mail3.py
      connect: (‘localhost’, 25)
      connect: to (‘localhost’, 25) None
      reply: b’220 new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:30:47 -0700\r\n’
      reply: retcode (220); Msg: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:30:47 -0700′
      connect: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:30:47 -0700′
      Traceback (most recent call last):
      File “./mail3.py”, line 27, in
      result = s.send_message(msg)
      File “/usr/lib64/python3.4/smtplib.py”, line 844, in send_message
      to_addrs = [a[1] for a in email.utils.getaddresses(addr_fields)]
      File “/usr/lib64/python3.4/email/utils.py”, line 112, in getaddresses
      all = COMMASPACE.join(fieldvalues)
      TypeError: sequence item 0: expected str instance, list found
      You have new mail in /var/spool/mail/simberg
      ******************************************************

      With parentheses and comma:

      connect: (‘localhost’, 25)
      connect: to (‘localhost’, 25) None
      reply: b’220 new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:30:47 -0700\r\n’
      reply: retcode (220); Msg: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:30:47 -0700′
      connect: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:30:47 -0700′
      Traceback (most recent call last):
      File “./mail3.py”, line 27, in
      result = s.send_message(msg)
      File “/usr/lib64/python3.4/smtplib.py”, line 844, in send_message
      to_addrs = [a[1] for a in email.utils.getaddresses(addr_fields)]
      File “/usr/lib64/python3.4/email/utils.py”, line 112, in getaddresses
      all = COMMASPACE.join(fieldvalues)
      TypeError: sequence item 0: expected str instance, list found
      You have new mail in /var/spool/mail/simberg
      [simberg@new-host-5 Python]$ ./mail3.py
      connect: (‘localhost’, 25)
      connect: to (‘localhost’, 25) None
      reply: b’220 new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:32:14 -0700\r\n’
      reply: retcode (220); Msg: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:32:14 -0700′
      connect: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:32:14 -0700′
      Traceback (most recent call last):
      File “./mail3.py”, line 27, in

      result = s.send_message(msg)
      File “/usr/lib64/python3.4/smtplib.py”, line 844, in send_message
      to_addrs = [a[1] for a in email.utils.getaddresses(addr_fields)]
      File “/usr/lib64/python3.4/email/utils.py”, line 112, in getaddresses
      all = COMMASPACE.join(fieldvalues)
      TypeError: sequence item 0: expected str instance, tuple found
      *********************************************

      With parentheses, no comma:

      connect: (‘localhost’, 25)
      connect: to (‘localhost’, 25) None
      reply: b’220 new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:32:29 -0700\r\n’
      reply: retcode (220); Msg: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:32:29 -0700′
      connect: b’new-host-5.home ESMTP Sendmail 8.15.2/8.15.2; Fri, 15 Apr 2016 15:32:29 -0700′
      send: ‘ehlo new-host-5.home\r\n’
      reply: b’250-new-host-5.home Hello localhost.localdomain [127.0.0.1], pleased to meet you\r\n’
      reply: b’250-ENHANCEDSTATUSCODES\r\n’
      reply: b’250-PIPELINING\r\n’
      reply: b’250-8BITMIME\r\n’
      reply: b’250-SIZE\r\n’
      reply: b’250-DSN\r\n’
      reply: b’250-ETRN\r\n’
      reply: b’250-AUTH GSSAPI DIGEST-MD5 CRAM-MD5\r\n’
      reply: b’250-DELIVERBY\r\n’
      reply: b’250 HELP\r\n’
      reply: retcode (250); Msg: b’new-host-5.home Hello localhost.localdomain [127.0.0.1], pleased to meet you\nENHANCEDSTATUSCODES\nPIPELINING\n8BITMIME\nSIZE\nDSN\nETRN\nAUTH GSSAPI DIGEST-MD5 CRAM-MD5\nDELIVERBY\nHELP’
      send: ‘mail FROM: size=192\r\n’
      reply: b’250 2.1.0
      … Sender ok\r\n’
      reply: retcode (250); Msg: b’2.1.0
      … Sender ok’
      send: ‘rcpt TO:
      \r\n’
      reply: b’250 2.1.5
      … Recipient ok\r\n’
      reply: retcode (250); Msg: b’2.1.5
      … Recipient ok’
      send: ‘data\r\n’
      reply: b’354 Enter mail, end with “.” on a line by itself\r\n’
      reply: retcode (354); Msg: b’Enter mail, end with “.” on a line by itself’
      data: (354, b’Enter mail, end with “.” on a line by itself’)
      send: b’Content-Type: text/plain; charset=”us-ascii”\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nSubject: Test\r\nFrom: simberg@interglobal.org\r\nTo: simberg@interglobal.org\r\n\r\nThis is a test.\r\n.\r\n’
      reply: b’250 2.0.0 u3FMWTEk013027 Message accepted for delivery\r\n’
      reply: retcode (250); Msg: b’2.0.0 u3FMWTEk013027 Message accepted for delivery’
      data: (250, b’2.0.0 u3FMWTEk013027 Message accepted for delivery’)
      after send_message
      {}
      s has been opened
      after send_message
      End script
      ****************************

      In none of the cases is mail sent.

      1. Well, the python script part looks okay, as you are actually getting 250 Message accepted for delivery back from your local Sendmail server instance.
        Why is your local sendmail not sending anything out is a different story.
        If you point the python script at another properly routing STMP server it’l send it out – but a remote service will require account authentication as shown in the gist.github link with the gmail example.

  6. send: ‘mail FROM: size=192\r\n’
    reply: b’250 2.1.0 … Sender ok\r\n’
    reply: retcode (250); Msg: b’2.1.0 … Sender ok’
    send: ‘rcpt TO:\r\n’
    reply: b’250 2.1.5 … Recipient ok\r\n’

    Unless you or the logger are stripping out the email address, you’re not actually specifying a sender or a recipient. The log should have read

    send: ‘rcpt TO: <simberg@interglobal.org>\r\n’

    Same for the sender.

  7. I’ve done something similar before with os.system(‘mail [stuff]’); Basically, calling the command line mail application.

Comments are closed.