88import uuid
99import warnings
1010from email .mime .base import MIMEBase
11- from typing import TYPE_CHECKING , Dict , Iterable , Optional , Tuple , Union
11+ from typing import TYPE_CHECKING , Any , Dict , Iterable , List , Optional , Tuple , Union
1212
1313from django .conf import settings
1414from django .core .exceptions import ImproperlyConfigured
3434)
3535
3636from sendgrid_backend .signals import sendgrid_email_sent
37- from sendgrid_backend .util import SENDGRID_5 , SENDGRID_6 , get_django_setting
37+ from sendgrid_backend .util import (
38+ SENDGRID_5 ,
39+ SENDGRID_6 ,
40+ dict_to_personalization ,
41+ get_django_setting ,
42+ )
3843
3944DjangoAttachment = Union [Tuple [str , Union [bytes , str ], str ], MIMEBase ]
4045
@@ -242,10 +247,10 @@ def _parse_email_address(self, address: str) -> Tuple[str, Optional[str]]:
242247
243248 def _build_sg_personalization (
244249 self ,
245- to : Iterable [ str ],
250+ to : List [ Any ],
246251 msg : EmailMessage ,
247252 extra_headers : Iterable [Header ],
248- personalizations : Dict = None ,
253+ existing_personalizations : Optional [ Personalization ] = None ,
249254 ) -> Personalization :
250255 """
251256 Constructs a Sendgrid Personalization instance / row for the given recipients.
@@ -257,41 +262,44 @@ def _build_sg_personalization(
257262 to: The email addresses for the given personalization.
258263 msg: The base Django Email message object - used to fill (missing) personalization data
259264 extra_headers: The non "reply-to" headers for the personalization.
260- personalizations : Personalization data, eg. dynamic_template_data or substitutions.
265+ existing_personalizations : Personalization data, eg. dynamic_template_data or substitutions.
261266 A given value should have key equivalent to corresponding msg attr
262267
263268
264269 Returns:
265270 A sendgrid personalization instance
266271 """
272+ personalization = existing_personalizations or Personalization ()
267273
268- personalizations = personalizations or {}
269- personalization = Personalization ()
270-
271- for addr in msg .to :
272- personalization .add_to (Email (* self ._parse_email_address (addr )))
274+ if to :
275+ if type (to [0 ]) == str :
276+ for addr in to :
277+ personalization .add_to (Email (* self ._parse_email_address (addr )))
278+ else :
279+ personalization .tos = to
273280
274- for addr in personalizations .get ("cc" ) or msg .cc :
275- personalization .add_cc (Email (* self ._parse_email_address (addr )))
281+ if not personalization .ccs :
282+ for addr in msg .cc :
283+ personalization .add_cc (Email (* self ._parse_email_address (addr )))
276284
277- for addr in personalizations .get ("bcc" ) or msg .bcc :
278- personalization .add_bcc (Email (* self ._parse_email_address (addr )))
285+ if not personalization .bccs :
286+ for addr in msg .bcc :
287+ personalization .add_bcc (Email (* self ._parse_email_address (addr )))
279288
280- for k , v in personalizations .get (
281- "custom_args" ,
282- getattr (msg , "custom_args" , {}),
283- ).items ():
284- personalization .add_custom_arg (CustomArg (k , v ))
289+ if not personalization .custom_args :
290+ for k , v in getattr (msg , "custom_args" , {}).items ():
291+ personalization .add_custom_arg (CustomArg (k , v ))
285292
286293 if self ._is_transaction_template (msg ):
287- if msg .subject :
294+ if personalization . subject or msg .subject :
288295 logger .warning (
289296 "Message subject is ignored in transactional template, "
290297 "please add it as template variable (e.g. {{ subject }}"
291298 )
292299 # See https://github.com/sendgrid/sendgrid-nodejs/issues/843
293- else :
294- personalization .subject = personalizations .get ("subject" ) or msg .subject
300+
301+ if not personalization .subject :
302+ personalization .subject = msg .subject
295303
296304 for header in extra_headers :
297305 personalization .add_header (header )
@@ -308,15 +316,12 @@ def _build_sg_personalization(
308316 personalization .send_at = msg .send_at
309317
310318 if hasattr (msg , "template_id" ):
311- for k , v in personalizations .get (
312- "substitutions" ,
313- getattr (msg , "substitutions" , {}),
314- ).items ():
315- personalization .add_substitution (Substitution (k , v ))
316-
317- dtd = personalizations .get (
318- "dynamic_template_data" ,
319- getattr (msg , "dynamic_template_data" , None ),
319+ if not personalization .substitutions :
320+ for k , v in getattr (msg , "substitutions" , {}).items ():
321+ personalization .add_substitution (Substitution (k , v ))
322+
323+ dtd = personalization .dynamic_template_data or getattr (
324+ msg , "dynamic_template_data" , None
320325 )
321326 if dtd :
322327 if SENDGRID_5 :
@@ -420,13 +425,17 @@ def _build_sg_mail(self, msg: EmailMessage) -> Dict:
420425
421426 if hasattr (msg , "personalizations" ):
422427 for personalization in msg .personalizations :
423- to = personalization .pop ("to" )
428+ if type (personalization ) == Dict :
429+ personalization = dict_to_personalization (personalization )
430+
431+ assert type (personalization ) == Personalization
432+
424433 mail .add_personalization (
425434 self ._build_sg_personalization (
426- to ,
435+ personalization . tos or msg . to ,
427436 msg ,
428437 personalization_headers ,
429- personalizations = personalization ,
438+ existing_personalizations = personalization ,
430439 )
431440 )
432441 elif getattr (msg , "make_private" , False ):
0 commit comments