Skip to content

Commit

Permalink
Resend: workaround display-name bug
Browse files Browse the repository at this point in the history
  • Loading branch information
medmunds committed Sep 29, 2023
1 parent 9b7c85c commit 6af3cb8
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
32 changes: 29 additions & 3 deletions anymail/backends/resend.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import mimetypes
from email.charset import QP, Charset
from email.utils import formataddr

from ..message import AnymailRecipientStatus
from ..utils import CaseInsensitiveCasePreservingDict, get_anymail_setting
from .base_requests import AnymailRequestsBackend, RequestsPayload

# Used to force RFC-2047 encoded word
# in address formatting workaround
QP_CHARSET = Charset("utf-8")
QP_CHARSET.header_encoding = QP


class EmailBackend(AnymailRequestsBackend):
"""
Expand Down Expand Up @@ -69,22 +76,41 @@ def serialize_data(self):
def init_payload(self):
self.data = {} # becomes json

@staticmethod
def _resend_email_address(address):
"""
Return EmailAddress address formatted for use with Resend.
Works around a Resend bug that rejects properly formatted RFC 5822
addresses that have the display-name enclosed in double quotes (e.g.,
any display-name containing a comma).
"""
formatted = address.address
if formatted.startswith('"'):
# Workaround: force RFC-2047 encoded word
formatted = formataddr(
(QP_CHARSET.header_encode(address.display_name), address.addr_spec)
)
return formatted

def set_from_email(self, email):
self.data["from"] = email.address
self.data["from"] = self._resend_email_address(email)

def set_recipients(self, recipient_type, emails):
assert recipient_type in ["to", "cc", "bcc"]
if emails:
field = recipient_type
self.data[field] = [email.address for email in emails]
self.data[field] = [self._resend_email_address(email) for email in emails]
self.recipients += emails

def set_subject(self, subject):
self.data["subject"] = subject

def set_reply_to(self, emails):
if emails:
self.data["reply_to"] = [email.address for email in emails]
self.data["reply_to"] = [
self._resend_email_address(email) for email in emails
]

def set_extra_headers(self, headers):
self.data.setdefault("headers", {}).update(headers)
Expand Down
31 changes: 31 additions & 0 deletions tests/test_resend_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,37 @@ def test_name_addr(self):
data["bcc"], ["Blind Copy <[email protected]>", "[email protected]"]
)

def test_quoted_display_names(self):
# Resend's API has a bug that rejects a display-name that is quoted
# (per RFC 5822 section 3.4). Attempting to omit the quotes works, unless
# the display-name also contains a comma. Try to avoid the whole problem
# by using RFC 2047 encoded words for addresses Resend will parse incorrectly.
msg = mail.EmailMessage(
"Subject",
"Message",
'"From, comma" <[email protected]>',
[
'"To, comma" <[email protected]>',
"non–ascii <[email protected]>",
"=?utf-8?q?pre_encoded?= <[email protected]>",
],
reply_to=['"Reply, comma" <[email protected]>'],
)
msg.send()
data = self.get_api_call_json()
self.assertEqual(data["from"], "=?utf-8?q?From=2C_comma?= <[email protected]>")
self.assertEqual(
data["to"],
[
"=?utf-8?q?To=2C_comma?= <[email protected]>",
"=?utf-8?b?bm9u4oCTYXNjaWk=?= <[email protected]>",
"=?utf-8?q?pre_encoded?= <[email protected]>",
],
)
self.assertEqual(
data["reply_to"], ["=?utf-8?q?Reply=2C_comma?= <[email protected]>"]
)

def test_email_message(self):
email = mail.EmailMessage(
"Subject",
Expand Down

0 comments on commit 6af3cb8

Please sign in to comment.