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
Is There a Module for Balanced Binary Tree in Python's Standard Library
I'm Getting "Typeerror: 'List' Object Is Not Callable". How to Fix This Error
Add Column with Number of Days Between Dates in Dataframe Pandas
Simulate Python Keypresses for Controlling a Game
How to Specify "Nullable" Return Type with Type Hints
Selecting Pandas Column by Location
How Do Chained Comparisons in Python Actually Work
How to Integrate Flask & Scrapy
How to Schedule a Function to Run Every Hour on Flask
How to Find Tags with Only Certain Attributes - Beautifulsoup
Minimum Euclidean Distance Between Points in Two Different Numpy Arrays, Not Within
Convert Python Strings into Floats Explicitly Using the Comma or the Point as Separators
How to Do N-D Distance and Nearest Neighbor Calculations on Numpy Arrays
In Python, How to Escape Newline Characters When Printing a String
Python Argparse Ignore Unrecognised Arguments
Select Multiple Ranges of Columns in Pandas Dataframe