Reputation: 2388
I currently trying to send e-mails from a python script to a set of recipients that a got from a database (name + email address) and I want so send the mails such that their name is also included in the message header. But if the name includes an umlaut (äöü...) my script fails with (in case there is an ü inside the name):
UnicodeEncodeError: 'ascii' codec can't encode character '\xfc' in position 5: ordinal not in range(128)
But in the content of the message all umlauts are correctly replaced with for example =C3=BC
for the ü
.
Here is the example code I used:
import smtplib
from email.message import EmailMessage
from email.headerregistry import Address
from email.utils import make_msgid
msg = EmailMessage()
msg["Subject"] = "Python Test"
msg["From"] = Address("Max Müller" , addr_spec="[email protected]")
msg["To"] = Address("Max Möller", addr_spec="[email protected]")
msg.set_content("""\
This is a test with umlauts. öäü
--- Max Müller """)
server = smtplib.SMTP('localhost', 25)
server.send_message(msg)
server.quit()
I tried it with Python 3.5.2.
If replace
msg["From"] = Address("Max Müller" , addr_spec="[email protected]")
by
msg["From"] = Address("Max Müller".encode("utf-8") , addr_spec="[email protected]")
I got in my mail client as senders name b'Max M\xc3\xbcller'
which is useless to the most e-mail clients.
So how do I get the umlauts in the recipient's and the sender's encoded as in the mail's content?
Upvotes: 5
Views: 2079
Reputation: 148880
Almost all was fine, but the send_message
method is not really non-ASCII friendly, so you must use the good old sendmail
. The problem is that send_message
tries to use the content of the To
and From
headers to build the envelope addresses but unfortunately it is broken for addresses containing non ASCII characters even if they are in the name part.
So if you have only one recipient address, you code should simply be:
...
server.sendmail(msg["From"], msg["To"], msg.as_string())
If you want to be able to process multiple recipient addresses, you must add an explicit processing:
def envelopeAddr(header):
return [a.addr_spec for a in header.addresses]
The sendmail command becomes:
server.sendmail(msg["From"], envelopeAddr(msg["To"]), msg.as_string())
The good new is that it also works for a single dest address.
Upvotes: 6
Reputation: 482
def dd_b64(s):
s = '=?utf-8?b?' + base64.b64encode(s.encode('UTF-8')).decode() + '?='
s = '=?utf-8?b?' + base64.b64encode(s.encode('UTF-8')).decode() + '?='
return s
msg = EmailMessage()
#msg['From'] = Address(dd_b64(发送者昵称), *发送者账号.rsplit('@', 1))
msg['From'] = Address(dd_b64(发送者昵称), addr_spec = 发送者账号) #省略addr_spec会出现 由 [email protected] 代发
msg['To'] = Group(None, [Address(dd_b64(name), to_addrs)])
msg['Subject'] = '63中文'
msg['Date'] = localtime()
===========================================================================
double encode b64 to "From,To,and add_attachment's filename"
msg["From"] = Address(dd_b64("Max Müller") , addr_spec="[email protected]")
msg["To"] also dd_b64.
msg.add_attachment(fi.read(), *ctype.split('/', 1), filename = dd_b64('工作表.xlsx'))
Upvotes: 2