Skip to content

Commit e524180

Browse files
committed
Support RFC 6532 (non ascii characters in email). Fixes #138
1 parent eecc9ed commit e524180

8 files changed

Lines changed: 29 additions & 12 deletions

File tree

.github/workflows/tests.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- {name: '2.7', python: '2.7', os: ubuntu-16.04, tox: py27}
2323
services:
2424
postfix:
25-
image: juanluisbaptiste/postfix
25+
image: lavr/docker-postfix
2626
env:
2727
SMTP_SERVER: smtp.gmail.com
2828
SMTP_PORT: 587
@@ -53,11 +53,13 @@ jobs:
5353
- name: run rests
5454
env:
5555
SMTP_TEST_SUBJECT_SUFFIX: "github-actions sha:${{ github.sha }} run_id:${{ github.run_id }}"
56+
SMTP_TEST_MAIL_FROM: python-emails-tests@lavr.me
57+
SMTP_TEST_MAIL_TO: python-emails-tests@lavr.me
5658
SMTP_TEST_SETS: LOCAL
57-
SMTP_TEST_LOCAL_TO: python-emails-tests@lavr.me
5859
SMTP_TEST_LOCAL_WITHOUT_TLS: true
5960
SMTP_TEST_LOCAL_HOST: 127.0.0.1
6061
SMTP_TEST_LOCAL_PORT: 2525
62+
6163
SMTP_TEST_GMAIL_TO: python-emails-tests@lavr.me
6264
SMTP_TEST_GMAIL_USER: ${{ secrets.SMTP_TEST_GMAIL_USER }}
6365
SMTP_TEST_GMAIL_PASSWORD: ${{ secrets.SMTP_TEST_GMAIL_PASSWORD }}

emails/backend/smtp/backend.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class SMTPBackend(object):
2626
connection_ssl_cls = SMTPClientWithResponse_SSL
2727
response_cls = SMTPResponse
2828

29-
def __init__(self, ssl=False, fail_silently=True, **kwargs):
29+
def __init__(self, ssl=False, fail_silently=True, mail_options=None, **kwargs):
3030

3131
self.smtp_cls = ssl and self.connection_ssl_cls or self.connection_cls
3232

@@ -46,6 +46,7 @@ def __init__(self, ssl=False, fail_silently=True, **kwargs):
4646
self.host = kwargs.get('host')
4747
self.port = kwargs.get('port')
4848
self.fail_silently = fail_silently
49+
self.mail_options = mail_options or []
4950

5051
self._client = None
5152

@@ -119,7 +120,7 @@ def sendmail(self, from_addr, to_addrs, msg, mail_options=None, rcpt_options=Non
119120
response = send(from_addr=from_addr,
120121
to_addrs=to_addrs,
121122
msg=msg.as_string(),
122-
mail_options=mail_options,
123+
mail_options=mail_options or self.mail_options,
123124
rcpt_options=rcpt_options)
124125

125126
if not self.fail_silently:

emails/compat/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,10 @@ def formataddr(pair):
160160
Does not encode non-ascii realname.
161161
162162
Python3 email.utils.formataddr do encode realname.
163+
164+
TODO: switch to email.headerregistry.AddressHeader ?
163165
"""
166+
164167
name, address = pair
165168
if name:
166169
quotes = ''

emails/testsuite/message/helpers.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
import emails
66
from emails.template import JinjaTemplate
77

8-
TO_EMAIL = os.environ.get('TEST_TO_EMAIL') or 'python.emails.test.2@yandex.ru'
9-
FROM_EMAIL = os.environ.get('TEST_FROM_EMAIL') or 'python-emails@lavr.me'
8+
TO_EMAIL = os.environ.get('SMTP_TEST_MAIL_TO') or 'python.emails.test.2@yandex.ru'
9+
FROM_EMAIL = os.environ.get('SMTP_TEST_MAIL_FROM') or 'python-emails@lavr.me'
1010
ROOT = os.path.dirname(__file__)
1111

12+
1213
def common_email_data(**kw):
1314
T = JinjaTemplate
1415
data = {'charset': 'utf-8',

emails/testsuite/message/test_message.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ def test_message_addresses():
147147
assert m.mail_to == [("웃", "b@c.d"), (None, "e@f.g")]
148148

149149

150+
def test_rfc6532_address():
151+
m = Message()
152+
m.mail_to = "anaïs@example.com"
153+
m.html = 'X'
154+
assert m.as_string()
155+
156+
150157
def test_message_policy():
151158

152159
if is_py34_plus:

emails/testsuite/message/test_send.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,19 @@ def get_letters():
2626
del data['html']
2727
yield emails.loader.from_url(url=url, message_params=data, images_inline=True), None
2828

29+
# Email with utf-8 "to"
30+
yield emails.Message(**common_email_data(mail_to="anaïs@lavr.me", subject="UTF-8 To")), None
31+
2932

3033
def test_send_letters():
3134

3235
for m, render in get_letters():
3336
for tag, server in get_servers():
3437
server.patch_message(m)
3538
print(tag, server.params)
36-
response = m.send(smtp=server.params, render=render)
37-
print(server.params)
38-
assert response.success or response.status_code in (421, 451) # gmail not always like test emails
39-
server.sleep()
39+
response = m.send(smtp=server.params, render=render, smtp_mail_options=['smtputf8'])
40+
assert response.success
41+
# server.sleep()
4042

4143

4244
def test_send_with_context_manager():

emails/testsuite/smtp_servers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def _var(param, default=None):
4141
return v
4242

4343
def _valid_smtp(data):
44-
return data['to_email'] and data['host']
44+
return data['host']
4545

4646
smtp_info = dict(
4747
from_email=_var("FROM", default=DEFAULT_FROM),

emails/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
from email.mime.text import MIMEText
1313
from email.mime.multipart import MIMEMultipart
1414
from email.header import Header, decode_header as decode_header_
15-
from email.utils import formataddr, parseaddr, formatdate
15+
from email.utils import parseaddr, formatdate
16+
from emails.compat import formataddr
1617

1718
import requests
1819

0 commit comments

Comments
 (0)