Smtplib Sends Blank Message If the Message Contain Certain Characters

smtplib sends blank message if the message contain certain characters

The problem is that smtplib is not putting a blank line between the message header and the message body as shown by in the "Show Original" form of my test:

Return-Path: <me@gmail.com>
Received: **REDACTED**
Fri, 03 Aug 2012 06:56:20 -0700 (PDT)
Message-ID: <501bd884.850c320b@mx.google.com>
Date: Fri, 03 Aug 2012 06:56:20 -0700 (PDT)
From: me@gmail.com
http: //www.example.com

Although this is a legal mail header, Mail Transfer Agents and Mail User Agents should ignore apparent header fields they don't understand. And because the RFC822 header continues until the first blank line and http: looks like a header line, it is parsed as if it were a header. If given a newline:

mensaje = '\nhttp://www.example.com'

Then it works as expected. Although email technically only needs the "envelope" as provided by smtplib the contents of the mail should be more complete if you expect your recipients (and their mailers) to treat the message nicely, you should probably use the email module to generate the body.

added

Based on the doctest in smtplib.py it looks as if this is an intentional feature allowing the caller of sendmail() to append to the header:

     >>> msg = '''\\
... From: Me@my.org
... Subject: testin'...
...
... This is a test '''
>>> s.sendmail("me@my.org", tolist, msg)

Where the From: and Subject: lines are part of the "nice" headers I mentioned above.

Python sending blank e-mails

The following question: smtplib sends blank message if the message contain certain characters, points out that you must start the content of the message with a new line or else the content will be part of the message's header and not the message's body.

I believe that you have to change:

content = "The person's name is: "

To this:

content = "\nThe person's name is: "

how to send symbols , numbers , text as a paragraph with smtp module?

I would recommend creating a separate file for paragraph responses and then importing the EmailMessage() class from smtplib which will allow you to pass that message to the email. I would recommend trying this:

import smtplib
from email.message import EmailMessage

# Open the plain text file.
txtfile = 'name_of_your_file'
with open(txtfile) as f_obj:
# Create a blank message and then add the contents of the
# file to it
msg = EmailMessage()
msg.set_content(f_obj.read())

msg['Subject'] = 'your_subject'
msg['From'] = me
msg['To'] = you

# Send the message through your own SMTP server.
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()

This will allow you to send any types of long messages because it saves the contents of the file as a string and then adds it to the file so there are no conversion errors.

Why does this Python program send empty emails when I encode it with utf-8?

The msg argument to smtplib.sendmail should be a bytes sequence containing a valid RFC5322 message. Taking a string and encoding it as UTF-8 is very unlikely to produce one (if it's already ASCII, encoding it does nothing useful; and if it isn't, you are most probably Doing It Wrong).

To explain why that is unlikely to work, let me provide a bit of background. The way to transport non-ASCII strings in MIME messages depends on the context of the string in the message structure. Here is a simple message with the word "Hëlló" embedded in three different contexts which require different encodings, none of which accept raw UTF-8 easily.

From: me <sender@example.org>
To: you <recipient@example.net>
Subject: =?utf-8?Q?H=C3=ABll=C3=B3?= (RFC2047 encoding)
MIME-Version: 1.0
Content-type: multipart/mixed; boundary="fooo"

--fooo
Content-type: text/plain; charset="utf-8"
Content-transfer-encoding: quoted-printable

H=C3=ABll=C3=B3 is bare quoted-printable (RFC2045),
like what you see in the Subject header but without
the RFC2047 wrapping.

--fooo
Content-type: application/octet-stream; filename*=UTF-8''H%C3%ABll%C3%B3

This is a file whose name has been RFC2231-encoded.

--fooo--

There are recent extensions which allow for parts of messages between conforming systems to contain bare UTF-8 (even in the headers!) but I have a strong suspicion that this is not the scenario you are in. Maybe tangentially see also https://en.wikipedia.org/wiki/Unicode_and_email

Returning to your code, I suppose it could work if base is coincidentally also the name of a header you want to add to the start of the message, and text contains a string with the rest of the message. You are not showing enough of your code to reason intelligently about this, but it seems highly unlikely. And if text already contains a valid MIME message, encoding it as UTF-8 should not be necessary or useful (but it clearly doesn't, as you get the encoding error).

Let's suppose base contains Subject and text is defined thusly:

text='''=?utf-8?B?H=C3=ABll=C3=B3?= (RFC2047 encoding)
MIME-Version: 1.0
Content-type: multipart/mixed; boundary="fooo"
....'''

Now, the concatenation base + ': ' + text actually produces a message similar to the one above (though I reordered some headers to put Subject: first for this scenario) but again, I imagine this is not how things actually are in your code.

If your goal is to send an extracted piece of text as the body of an email message, the way to do that is roughly

from email.message import EmailMessage

body_text = os.path.splitext(base)[0] + ': ' + text

message = EmailMessage()
message.set_content(body_text)
message["subject"] = "Extracted text"
message["from"] = "you@example.net"
message["to"] = "me@example.org"

with smtplib.SMTP("smtp.gmail.com", 587) as server:
# ... smtplib setup, login, authenticate?
server.send_message(message)

This answer was updated for the current email library API; the text below the line is the earlier code from the original answer.

The modern Python 3.3+ EmailMessage API rather straightforwardly translates into human concepts, unlike the older API which required you to understand many nitty-gritty details of how the MIME structure of your message should look.



from email.mime.text import MIMEText

body_text = os.path.splitext(base)[0] + ": " + text
sender = "you@example.net"
recipient = "me@example.org"

message = MIMEText(body_text)
message["subject"] = "Extracted text"
message["from"] = sender
message["to"] = recipient
server = smtplib.SMTP("smtp.gmail.com", 587)
# ... smtplib setup, login, authenticate?
server.sendmail(from, to, message.as_string())

The MIMEText() invocation builds an email object with room for a sender, a subject, a list of recipients, and a body; its as_text() method returns a representation which looks roughly similar to the ad hoc example message above (though simpler still, with no multipart structure) which is suitable for transmitting over SMTP. It transparently takes care of putting in the correct character set and applying suitable content-transfer encodings for non-ASCII header elements and body parts (payloads).

Python's standard library contains fairly low-level functions so you have to know a fair bit in order to connect all the pieces correctly. There are third-party libraries which hide some of this nitty-gritty; but you would exepect anything with email to have at the very least both a subject and a body, as well as of course a sender and recipients.

Empty message send with smtplib

I will bet that you have a problem with your country variable. If it is somehow set to something other than "CAN" or "USA" then the message and the subject will be blank.

You probably want to structure it something like this instead:

# can country be lower case? try using .upper()
if country is 'CAN':
# defining subject, text, and html in one block means you won't need to edit
# multiple spots if your logic changes.
subject = 'Inscription'
# yada
else: # handle all cases, including unknowns.
subject = 'Registration'

You also may want to handle the error for conn.sendmail.

getting a blank email

The message you pass as the third argument to sendmail needs to be a valid, properly formatted RFC822 message. A JSON file is, by definition, not a valid email message.

def sendMail(usr, pwd, to, body):
msg = MIMEText(body)
msg['From'] = usr
msg['To'] = to
msg['Subject'] = "Data add request"
try:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.ehlo()
server.login(usr, pwd)
server.send_message("error-report@do_not_reply.com", [to], msg)
except Exception, err:
print 'Error sending email: ', err
finally:
server.quit()

I switched to send_message here because it takes care of the minor mundane detail of converting the email.Message object to a string object again before calling sendmail.

It's not clear if you expect the body to be a text part displaying the contents of the string body, or a JSON attachment containing body as JSON, or perhaps both.

If you only need one body part, making the message multipart is obviously unnecessary. If you want multiple parts, then each of them should be a separate MIMEText or some other MIME container type which you can msg.attach() to a top-level MIMEMultipart.

Sending email with smtplib, no errors but no messages delivered

Please refer to my code. I have done this and it's working.
You can get some lead by refering my code.

Check main function code.

import smtplib

from string import Template

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

MY_ADDRESS = 'xyz@gmail.com'
PASSWORD = 'YourPassword'

def get_contacts(filename):
names = []
emails = []
with open(filename, mode='r', encoding='utf-8') as contacts_file:
for a_contact in contacts_file:
names.append(a_contact.split()[0])
emails.append(a_contact.split()[1])
return names, emails

def read_template(filename):
with open(filename, 'r', encoding='utf-8') as template_file:
template_file_content = template_file.read()
return Template(template_file_content)

def main():
names, emails = get_contacts('C:/Users/VAIBHAV/Desktop/mycontacts.txt') # read contacts
message_template = read_template('C:/Users/VAIBHAV/Desktop/message.txt')
s = smtplib.SMTP(host='smtp.gmail.com', port=587)
s.starttls()
s.login(MY_ADDRESS, PASSWORD)
for name, email in zip(names, emails):
msg = MIMEMultipart() # create a message
message = message_template.substitute(PERSON_NAME=name.title())
print(message)
msg['From'] = MY_ADDRESS
msg['To'] = email
msg['Subject'] = "Sending mail to all"
msg.attach(MIMEText(message, 'plain'))
s.send_message(msg)
del msg
s.quit()
if __name__ == '__main__':
main()

Python sending email without content

I think the answer given to the following question might be the solution.

The answer mentions that content should be started with a new line. If that's not the case the content becomes part of the message header rather than the message body.

And one more point I noticed is in the documentation of smtplib, it is given that from_address and to_address should follow the RFC822 format. Once you check whether you are correctly following that format or not.

So I don't know if this would work or not, try changing "from_address" to "<"+"from_address"+">".



Related Topics



Leave a reply



Submit