mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 03:41:05 -05:00
Mailgun, SparkPost: support multiple from_email addresses
[RFC-5322 allows](https://tools.ietf.org/html/rfc5322#section-3.6.2) multiple addresses in the From header. Django's SMTP backend supports this, as a single comma-separated string (*not* a list of strings like the recipient params): from_email='one@example.com, two@example.com' to=['one@example.com', 'two@example.com'] Both Mailgun and SparkPost support multiple From addresses (and Postmark accepts them, though truncates to the first one on their end). For compatibility with Django -- and because Anymail attempts to support all ESP features -- Anymail now allows multiple From addresses, too, for ESPs that support it. Note: as a practical matter, deliverability with multiple From addresses is pretty bad. (Google outright rejects them.) This change also reworks Anymail's internal ParsedEmail object, and approach to parsing addresses, for better consistency with Django's SMTP backend and improved error messaging. In particular, Django (and now Anymail) allows multiple email addresses in a single recipient string: to=['one@example.com', 'two@example.com, three@example.com'] len(to) == 2 # but there will be three recipients Fixes #60
This commit is contained in:
@@ -8,7 +8,7 @@ from django.utils.timezone import is_naive, get_current_timezone, make_aware, ut
|
||||
from ..exceptions import AnymailCancelSend, AnymailError, AnymailUnsupportedFeature, AnymailRecipientsRefused
|
||||
from ..message import AnymailStatus
|
||||
from ..signals import pre_send, post_send
|
||||
from ..utils import (Attachment, ParsedEmail, UNSET, combine, last, get_anymail_setting,
|
||||
from ..utils import (Attachment, UNSET, combine, last, get_anymail_setting, parse_address_list,
|
||||
force_non_lazy, force_non_lazy_list, force_non_lazy_dict, is_lazy)
|
||||
|
||||
|
||||
@@ -216,12 +216,12 @@ class BasePayload(object):
|
||||
# the combined/converted results for each attr.
|
||||
base_message_attrs = (
|
||||
# Standard EmailMessage/EmailMultiAlternatives props
|
||||
('from_email', last, 'parsed_email'),
|
||||
('to', combine, 'parsed_emails'),
|
||||
('cc', combine, 'parsed_emails'),
|
||||
('bcc', combine, 'parsed_emails'),
|
||||
('from_email', last, parse_address_list), # multiple from_emails are allowed
|
||||
('to', combine, parse_address_list),
|
||||
('cc', combine, parse_address_list),
|
||||
('bcc', combine, parse_address_list),
|
||||
('subject', last, force_non_lazy),
|
||||
('reply_to', combine, 'parsed_emails'),
|
||||
('reply_to', combine, parse_address_list),
|
||||
('extra_headers', combine, force_non_lazy_dict),
|
||||
('body', last, force_non_lazy), # special handling below checks message.content_subtype
|
||||
('alternatives', combine, 'prepped_alternatives'),
|
||||
@@ -266,6 +266,8 @@ class BasePayload(object):
|
||||
if value is not UNSET:
|
||||
if attr == 'body':
|
||||
setter = self.set_html_body if message.content_subtype == 'html' else self.set_text_body
|
||||
elif attr == 'from_email':
|
||||
setter = self.set_from_email_list
|
||||
else:
|
||||
# AttributeError here? Your Payload subclass is missing a set_<attr> implementation
|
||||
setter = getattr(self, 'set_%s' % attr)
|
||||
@@ -300,14 +302,6 @@ class BasePayload(object):
|
||||
# Attribute converters
|
||||
#
|
||||
|
||||
def parsed_email(self, address):
|
||||
return ParsedEmail(address, self.message.encoding) # (handles lazy address)
|
||||
|
||||
def parsed_emails(self, addresses):
|
||||
encoding = self.message.encoding
|
||||
return [ParsedEmail(address, encoding) # (handles lazy address)
|
||||
for address in addresses]
|
||||
|
||||
def prepped_alternatives(self, alternatives):
|
||||
return [(force_non_lazy(content), mimetype)
|
||||
for (content, mimetype) in alternatives]
|
||||
@@ -348,8 +342,17 @@ class BasePayload(object):
|
||||
raise NotImplementedError("%s.%s must implement init_payload" %
|
||||
(self.__class__.__module__, self.__class__.__name__))
|
||||
|
||||
def set_from_email_list(self, emails):
|
||||
# If your backend supports multiple from emails, override this to handle the whole list;
|
||||
# otherwise just implement set_from_email
|
||||
if len(emails) > 1:
|
||||
self.unsupported_feature("multiple from emails")
|
||||
# fall through if ignoring unsupported features
|
||||
if len(emails) > 0:
|
||||
self.set_from_email(emails[0])
|
||||
|
||||
def set_from_email(self, email):
|
||||
raise NotImplementedError("%s.%s must implement set_from_email" %
|
||||
raise NotImplementedError("%s.%s must implement set_from_email or set_from_email_list" %
|
||||
(self.__class__.__module__, self.__class__.__name__))
|
||||
|
||||
def set_to(self, emails):
|
||||
|
||||
Reference in New Issue
Block a user