M.K. aka Grisu
M.K. aka Grisu

Reputation: 2388

Send E-Mail from Python with umlaut in the in recipient's or sender's name

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

Answers (2)

Serge Ballesta
Serge Ballesta

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

ACE Fly
ACE Fly

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

Related Questions