Skip to content

Commit ef78681

Browse files
committed
Add reply_to parameter to Message (#115)
Support reply_to in the same way as cc/bcc: as a constructor parameter, a property, and a setter. Accepts a single address, a (name, email) tuple, or a list of addresses. The Reply-To header is rendered in the built message alongside To and Cc. Closes #115
1 parent 662cbc8 commit ef78681

2 files changed

Lines changed: 40 additions & 0 deletions

File tree

emails/message.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def __init__(self,
4848
attachments: list[dict[str, Any] | BaseFile] | None = None,
4949
cc: _AddressList = None,
5050
bcc: _AddressList = None,
51+
reply_to: _AddressList = None,
5152
headers_encoding: str | None = None) -> None:
5253

5354
self._attachments: MemoryFileStore | None = None
@@ -60,6 +61,7 @@ def __init__(self,
6061
self.set_mail_to(mail_to)
6162
self.set_cc(cc)
6263
self.set_bcc(bcc)
64+
self.set_reply_to(reply_to)
6365
self.set_headers(headers)
6466
self.set_html(html=html)
6567
self.set_text(text=text)
@@ -103,6 +105,14 @@ def get_bcc(self) -> list[tuple[str | None, str | None]]:
103105

104106
bcc = property(get_bcc, set_bcc)
105107

108+
def set_reply_to(self, addr: _AddressList) -> None:
109+
self._reply_to = parse_name_and_email_list(addr)
110+
111+
def get_reply_to(self) -> list[tuple[str | None, str | None]]:
112+
return self._reply_to
113+
114+
reply_to = property(get_reply_to, set_reply_to)
115+
106116
def get_recipients_emails(self) -> list[str | None]:
107117
"""
108118
Returns message recipient's emails for actual sending.
@@ -271,6 +281,9 @@ def _build_root_message(self, message_cls: type | None = None,
271281
if self.cc:
272282
self.set_header(msg, 'Cc', ", ".join([self.encode_address_header(addr) for addr in self.cc]), encode=False)
273283

284+
if self.reply_to:
285+
self.set_header(msg, 'Reply-To', ", ".join([self.encode_address_header(addr) for addr in self.reply_to]), encode=False)
286+
274287
return msg
275288

276289
def _build_html_part(self) -> SafeMIMEText | None:

emails/testsuite/message/test_message.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,33 @@ def test_message_id():
194194
assert m.as_message()['Message-ID'] == 'XXX'
195195

196196

197+
def test_reply_to():
198+
199+
params = dict(html='...', mail_from='a@b.c', mail_to='to@x.z')
200+
201+
# Single address
202+
m = Message(reply_to='reply@x.z', **params)
203+
assert m.as_message()['Reply-To'] == 'reply@x.z'
204+
205+
# Tuple (name, email)
206+
m = Message(reply_to=('Марья', 'maria@example.net'), **params)
207+
assert 'maria@example.net' in m.as_message()['Reply-To']
208+
209+
# Multiple addresses
210+
m = Message(reply_to=['a@x.z', 'b@x.z'], **params)
211+
assert 'a@x.z' in m.as_message()['Reply-To']
212+
assert 'b@x.z' in m.as_message()['Reply-To']
213+
214+
# No reply-to by default
215+
m = Message(**params)
216+
assert m.as_message()['Reply-To'] is None
217+
218+
# Setter
219+
m = Message(**params)
220+
m.reply_to = 'reply@x.z'
221+
assert m.as_message()['Reply-To'] == 'reply@x.z'
222+
223+
197224
def test_several_recipients():
198225

199226
# Test multiple recipients in "To" header

0 commit comments

Comments
 (0)