问题
I have put together a function send_email
[1] to send emails with support for plain-text and html messages. It works well, but I have an issue I don't quite know how to debug. My system has sendmail
as its MTA.
The function is called in a for loop, as follows:
for data in data_set:
subject, message = process(data) # Irrelevant stuff
send_email(subject, message, "fixed@email.address")
In the debug output of smtplib
[1] I see that all calls to send_email
completed successfully. The weird behavior is:
- If the
message
is "short" (I tested with a single line), all sent messages actually arrive tofixed@email.address
- If the
message
is "not short" (that is, the multiple lines I generate with the realprocess_data
function), only the first email does arrive, while the others don't, even though the debug output ofsmtplib
in [1] reports success for each and all of the emails. - If the
message
is equally "not short" but the destination address is different for each message, then all messages arrive to their intended destinations.
For the latter case, the for
loop would look like:
addresses = ["fixed@email.address", "fixed.2@email.address", ...]
for data, addr in zip(data_set, addresses):
subject, message = process(data) # Irrelevant stuff
send_email(subject, message, addr)
The intended behavior is of course different addresses for different data, but I'm concerned that not understanding why this happens might bite me in an unexpected way later on.
[1] My send mail function:
import smtplib
import socket
import getpass
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def send_email (subject, message, to, reply_to='', cc='', html_message=''):
COMMASPACE = ", "
user, host = get_user_and_host_names()
sender = '%s@%s' % (user, host)
receivers = make_address_list(to)
copies = make_address_list(cc)
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = COMMASPACE.join(receivers)
if reply_to:
msg.add_header('Reply-to', reply_to)
if len(copies):
msg.add_header('CC', COMMASPACE.join(copies))
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
if message:
msg.attach( MIMEText(message, 'plain'))
if html_message:
msg.attach( MIMEText(html_message, 'html'))
smtpObj = smtplib.SMTP('localhost')
smtpObj.set_debuglevel(1)
smtpObj.sendmail(sender, receivers, msg.as_string())
smtpObj.quit()
print "\nSuccessfully sent email to:", COMMASPACE.join(receivers)
def get_user_and_host_names():
user = getpass.getuser()
host = socket.gethostname()
return user, host
def make_address_list (addresses):
if isinstance(addresses, str):
receivers = addresses.replace(' ','').split(',')
elif isinstance(addresses, list):
receivers = addresses
return receivers
回答1:
A working solution I had for sending email:
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import smtplib
class EMail(object):
""" Class defines method to send email
"""
def __init__(self, mailFrom, server, usrname, password, files, debug=False):
self.debug = debug
self.mailFrom = mailFrom
self.smtpserver = server
self.EMAIL_PORT = 587
self.usrname = usrname
self.password = password
def sendMessage(self, subject, msgContent, files, mailto):
""" Send the email message
Args:
subject(string): subject for the email
msgContent(string): email message Content
files(List): list of files to be attached
mailto(string): email address to be sent to
"""
msg = self.prepareMail(subject, msgContent, files, mailto)
# connect to server and send email
server=smtplib.SMTP(self.smtpserver, port=self.EMAIL_PORT)
server.ehlo()
# use encrypted SSL mode
server.starttls()
# to make starttls work
server.ehlo()
server.login(self.usrname, self.password)
server.set_debuglevel(self.debug)
try:
failed = server.sendmail(self.mailFrom, mailto, msg.as_string())
except Exception as er:
print er
finally:
server.quit()
def prepareMail(self, subject, msgHTML, attachments, mailto):
""" Prepare the email to send
Args:
subject(string): subject of the email.
msgHTML(string): HTML formatted email message Content.
attachments(List): list of file paths to be attached with email.
"""
msg = MIMEMultipart()
msg['From'] = self.mailFrom
msg['To'] = mailto
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
#the Body message
msg.attach(MIMEText(msgHTML, 'html'))
msg.attach(MIMEText("Add signature here"))
if attachments:
for phile in attachments:
# we could check for MIMETypes here
part = MIMEBase('application',"octet-stream")
part.set_payload(open(phile, "rb").read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(phile))
msg.attach(part)
return msg
I hope this helps.
回答2:
My Working solution to format your list in this manner (after many hours of experiment):
["firstemail@mail.com", "secondmail@mail.com", "thirdmail@email.com"]
I used:
to_address = list(str(self.to_address_list).split(","))
to convert my QString into string then into list with splitting with a ","
In my case COMMASPACE was not working, because on splitting a space was already added by default.
来源:https://stackoverflow.com/questions/24550891/python-smtplib-only-the-first-email-out-of-several-arrives-to-destination