Понадобилось недавно наладить отправку электронной почты с сайта на django. Но оказалось все не так очевидно, как казалось в самом начале.
Я решил проверить на этом коде
import smtplib
from email.mime.text import MIMEText
from email.header import Header
def run():
noreply = 'no**ly@промик.рф'
smtp_host = 'smtp.yandex.ru'
login, password = noreply, '***'
recipients_emails = [noreply]
msg = MIMEText('Hello!', 'plain', 'utf-8')
msg['Subject'] = Header('Subject', 'utf-8')
msg['From'] = login
msg['To'] = ", ".join(recipients_emails)
s = smtplib.SMTP(smtp_host, 587, timeout=10)
try:
s.starttls()
s.login(login, password)
s.sendmail(msg['From'], recipients_emails, msg.as_string())
finally:
s.quit()
И получил ошибку:
UnicodeEncodeError: 'ascii' codec can't encode characters in position 9-14: ordinal not in range(128)
Тут-то я сразу понял, что дело в моем кириллическом домене и отправку нужно совершать на адрес в punycode. Мои изыскания привели меня к методу encode с кодировкой ‘idna’.
В использовании есть небольшие нюансы. Этот метод не стоит применить ко всему адресу почты, если в нем только кириллический домен. Вот, смотрите, что получилось:
>>> noreply = 'no**ly@промик.рф'
>>> print(noreply.encode('idna').decode('utf-8'))
xn--no**ly@-b9guuxmo.xn--p1ai
В части адреса явно закралось что-то лишнее. Поэтому я решил написать небольшую функцию, которая кодирует адрес почты в punycode:
>>> noreply = 'no**ly@промик.рф'
>>> def mail2punycode(mail):
... import re
...
... return "%s%s" % (re.sub(r'@.*$', '@', mail), mail.split('@')[1].encode('idna').decode('utf-8'))
...
>>> print(mail2punycode(noreply))
no**ly@xn--h1aeeheg.xn--p1ai
В итоге, почта стала отправляться без каких-либо проблем.
Кстати, мы с девушкой запустили новый проект — путеводитель по скидкам промик.рф, заходите — будем рады. Сайт написан на django — для меня это новшество и, если честно, я просто кайфую от использования django 🙂