Aor
Aor

Reputation: 185

Python: smtplib incorrectly formats email when inside of a function, but it correctly formats it when the same code is run from outside of a function

For a reason which escapes me, whenever I try to send this email by calling a function, the email lacks a subject, lacks a "To:", and the email's body is offset by four spaces. However, when exactly the same code is run from directly within the body of a script, everything is formatted perfectly.

import smtplib

def send_email():
    sender = '[email protected]'
    receivers = ['[email protected]']

    message_header = """From: Me <[email protected]>
    To: Me <[email protected]>
    Subject: This is the messages's subject

    """

    message_body = 'This is the message\'s body'

    message = message_header + message_body

    try:
        smtpObj = smtplib.SMTP('server_name', 25)
        smtpObj.sendmail(sender, receivers, message)
        print("Successfully sent email")
    except OSError:
        print("Error: unable to send email")

send_email()

Upvotes: 1

Views: 1159

Answers (3)

chepner
chepner

Reputation: 531798

(This shows you how to fix your current code; my other answer shows you the right way to implement this.)


Each line in message_header but the first is preceded by 4 spaces, including the body after you concatenate the two strings:

>>> repr(message_header)
'"From: Me <[email protected]>\\n    To: Me <[email protected]>\\n    Subject: This is the messages\'s subject\\n\\n    "'

(I tested this in a UNIX environment, hence the \n shown here. I assume you are using a file with DOS line endings, which already uses \r\n that SMTP expects.)

Either eliminate them yourself:

def send_email():
    sender = '[email protected]'
    receivers = ['[email protected]']

    message_header = """From: Me <[email protected]>
To: Me <[email protected]>
Subject: This is the messages's subject

"""

which is ugly, or use textwrap.dedent:

def send_email():
    sender = '[email protected]'
    receivers = ['[email protected]']

    message_header = textwrap.dedent(
        """From: Me <[email protected]>
           To: Me <[email protected]>
           Subject: This is the messages's subject

        """)

This removes the same amount of whitespace from each line in its argument:

dedent(text)
    Remove any common leading whitespace from every line in `text`.

    This can be used to make triple-quoted strings line up with the left
    edge of the display, while still presenting them in the source code
    in indented form.

    Note that tabs and spaces are both treated as whitespace, but they
    are not equal: the lines "  hello" and "    hello" are
    considered to have no common leading whitespace.  (This behaviour is
    new in Python 2.5; older versions of this module incorrectly
    expanded tabs before searching for common leading whitespace.)

Even better, use '\r\n'.join to construct the string for you.

def send_email():
    sender = '[email protected]'
    receivers = ['[email protected]']

    headers = [
      'From: Me <[email protected]>',
      'To: Me <[email protected]>',
      "Subject: This is the message's subject"
    ]

    message_body = 'This is the message\'s body'

    message = '\r\n'.join(headers + ['', ''] + [message_body])

Upvotes: 2

chepner
chepner

Reputation: 531798

My other answer aside, you should be using the email package to generate the message, rather than trying to construct it manually.

def send_email():
    sender = '[email protected]'
    receivers = ['[email protected]']

    message_body = 'This is the message\'s body'

    msg = email.MIMEText(message_body)
    msg['Subject'] = "This is the message's subject"
    msg['From'] = 'Me <%s>' % (sender,)
    msg['To'] = ', '.join(receivers)


    try:
        smtpObj = smtplib.SMTP('server_name', 25)
        smtpObj.sendmail(sender, receivers, msg.as_string())
        print("Successfully sent email")
    except OSError:
        print("Error: unable to send email")

Upvotes: 2

Nick is tired
Nick is tired

Reputation: 7056

def send_email():
    ...
    message_header = """From: Me <[email protected]>
____To: Me <[email protected]>
____Subject: This is the messages's subject

____"""

vs:

message_header = """From: Me <[email protected]>
To: Me <[email protected]>
Subject: This is the messages's subject

"""

Note that there are spaces in your function because they are indented. I've highlighted them with underscores for you.

You can fix this using:

def send_email():
    ...
    message_header = """From: Me <[email protected]>
To: Me <[email protected]>
Subject: This is the messages's subject

"""

Upvotes: 1

Related Questions