2

How to send an e-mail to the international address via smtplib in Python?

If I use the following code

    try:
        server = None

        msg = MIMEMultipart('alternative')
        msg['From'] = formataddr((from_email_name, from_email))
        msg['To'] = Header(to_email, 'utf-8')
        msg['Subject'] = Header(subject, 'utf-8')

        plain_text_part = MIMEText(plain_text_body, 'plain', _charset='utf-8')
        msg.attach(plain_text_part)

        html_part = MIMEText(html_body, 'html', _charset='utf-8')
        msg.attach(html_part)

        server = smtplib.SMTP(smtp_server)
        server.starttls()
        server.login(from_email, from_email_password)
        server.sendmail(from_email, to_email, msg.as_string())
    finally:
        if server is not None:
            server.quit()

then the script fails on the following line when I call this code with ñoñó1234@server.com e-mail as a destination address (to_email):

server.sendmail(from_email, to_email, msg.as_string())

Output

'ascii' codec can't encode character u'\xf1' in position 9: ordinal not in range(128)

However if I change the sendmail function call to the following

server.sendmail(from_email, to_email.encode('utf-8'), msg.as_string())

it fails with the following error:

{'\xc3\xb1o\xc3\xb1\xc3\xb31234@server.com': (555, '5.5.2 Syntax error. i7sm368361lbo.39 - gsmtp')}

I'm using GMail's SMTP server to send these e-mails.

How can I fix it?

Thanks in advance.

FrozenHeart
  • 19,844
  • 33
  • 126
  • 242
  • Try this : msg['To'] = str(Header(to_email, 'utf-8')) Tell me if this works. – Prav001 Dec 02 '15 at 11:22
  • @Prav001 Unfortunately, it doesn't work. Note that the application crashes on the `sendmail` function call – FrozenHeart Dec 02 '15 at 11:55
  • May be you should try another encoding scheme other than `utf-8` ? – Iron Fist Dec 02 '15 at 13:15
  • @Iron Fist UTF-16 doesn't work either -- `{'\xff\xfe\xf1\x00o\x00\xf1\x00\xf3\x001\x002\x003\x004\x00@\x00s\x00e\x00r\x00v\x00e\x00r\x00.\x00c\x00o\x00m\x00': (555, '5.5.2 Syntax error. qp7sm484744lbc.24 - gsmtp')}` – FrozenHeart Dec 02 '15 at 13:17
  • Or...may be the format of the email address should be `Recipient Name ` ... taken from this http://stackoverflow.com/questions/4421866/cakephp-smtp-emails-syntax-error] .. – Iron Fist Dec 02 '15 at 13:19
  • Because, the error you are getting is not a syntax error, but rather a protocol error message from GSMTP server... – Iron Fist Dec 02 '15 at 13:22
  • @Iron Fist Already tried it via `msg['To'] = Header(formataddr((to_email, to_email)), 'utf-8')` -- it doesn't help – FrozenHeart Dec 02 '15 at 13:22
  • I was talking about `to_email = 'Recipient Name '` .. something like that and same goes for `from_email` – Iron Fist Dec 02 '15 at 13:30
  • Does it work with a non-international email address? – moooeeeep Dec 02 '15 at 13:30
  • Read this : http://blog.yimingliu.com/2008/11/26/email-servers-and-mail-from-syntax/ – Iron Fist Dec 02 '15 at 13:31
  • @moooeeeep Yes, it works for all non-international e-mail addresses – FrozenHeart Dec 02 '15 at 13:33
  • @Iron Fist It doesn't work anyway -- `{'Name <\xc3\xb1o\xc3\xb1\xc3\xb31234@server.com>': (555, '5.5.2 Syntax error. i13sm509119lfe.9 - gsmtp')}` – FrozenHeart Dec 02 '15 at 13:35
  • Can you try this coding map `cp1252` instead of `utf-8`? – Iron Fist Dec 02 '15 at 13:44
  • @Iron Fist It doesn't work either -- `{'Name <\xf1o\xf1\xf31234@server.com>': (555, '5.5.2 Syntax error. zc2sm494772lbb.40 - gsmtp')}` – FrozenHeart Dec 02 '15 at 13:49
  • 1
    Internationalized addresses are a special use case for which according to RFC 6530, server should announce a SMTPUTF8 capability, and client passes SMTPUTF8 option in its `MAIL` command. Python smtplib **can** pass SMTPUTF8 option if the server announces it and if programmer asks for. You should add `server.set_debuglevel(7)` immediatley after `server = smtplib.SMTP(smtp_server)` and report here the session transcript. – Serge Ballesta Dec 02 '15 at 14:40
  • @Serge Ballesta http://pastie.org/10598547. It seems that `smtplib` doesn't send this command to the server – FrozenHeart Dec 02 '15 at 14:59

1 Answers1

3

RFC 6533 - Overview and Framework for Internationalized Email states that server side:

An SMTP relay MUST

  • Either recognize the format explicitly, agreeing to do so via an ESMTP option, or
  • Reject the message or, if necessary, return a non-delivery notification message, so that the sender can make another plan.

And RFC 6531 - SMTP Extension for Internationalized Email says as precisions (extracts):

  • The EHLO keyword value associated with this extension is "SMTPUTF8"
  • One OPTIONAL parameter, SMTPUTF8, is added to the MAIL command.
  • If the envelope or message being sent requires the capabilities of the SMTPUTF8 extension, the SMTPUTF8-aware SMTP client MUST supply the SMTPUTF8 parameter with the MAIL command.

As the trace of the exchange with GMail SMTP server proves that it announces itself as a SMTPUTF8 compliant server, you just have to ask smtplib to give the SMTPUTF8 option in mail command. You only need to change the sendmail command to:

server.sendmail(from_email, to_email.encode('utf-8'), msg.as_string(), ['SMTPUTF8'])

As you already process eventual non ASCII characters in body and set appropriate headers with MIMEMultipart and MIMEText all should be Ok.

Community
  • 1
  • 1
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252