Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/sendgrid/helpers/mail/mail.py: 36%
468 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""Twilio SendGrid v3/mail/send response body builder"""
2from .bcc_email import Bcc
3from .cc_email import Cc
4from .content import Content
5from .custom_arg import CustomArg
6from .dynamic_template_data import DynamicTemplateData
7from .email import Email
8from .from_email import From
9from .header import Header
10from .mime_type import MimeType
11from .personalization import Personalization
12from .reply_to import ReplyTo
13from .send_at import SendAt
14from .subject import Subject
15from .substitution import Substitution
16from .template_id import TemplateId
17from .to_email import To
20class Mail(object):
21 """Creates the response body for v3/mail/send"""
23 def __init__(
24 self,
25 from_email=None,
26 to_emails=None,
27 subject=None,
28 plain_text_content=None,
29 html_content=None,
30 amp_html_content=None,
31 global_substitutions=None,
32 is_multiple=False):
33 """
34 Creates the response body for a v3/mail/send API call
36 :param from_email: The email address of the sender
37 :type from_email: From, tuple, optional
38 :param subject: The subject of the email
39 :type subject: Subject, optional
40 :param to_emails: The email address of the recipient
41 :type to_emails: To, str, tuple, list(str), list(tuple),
42 list(To), optional
43 :param plain_text_content: The plain text body of the email
44 :type plain_text_content: string, optional
45 :param html_content: The html body of the email
46 :type html_content: string, optional
47 :param amp_html_content: The amp-html body of the email
48 :type amp_html_content: string, optional
49 """
50 self._attachments = None
51 self._categories = None
52 self._contents = None
53 self._custom_args = None
54 self._headers = None
55 self._personalizations = []
56 self._sections = None
57 self._asm = None
58 self._batch_id = None
59 self._from_email = None
60 self._ip_pool_name = None
61 self._mail_settings = None
62 self._reply_to = None
63 self._send_at = None
64 self._subject = None
65 self._template_id = None
66 self._tracking_settings = None
68 # Minimum required data to send a single email
69 if from_email is not None: 69 ↛ 71line 69 didn't jump to line 71, because the condition on line 69 was never false
70 self.from_email = from_email
71 if to_emails is not None: 71 ↛ 73line 71 didn't jump to line 73, because the condition on line 71 was never false
72 self.add_to(to_emails, global_substitutions, is_multiple)
73 if subject is not None: 73 ↛ 74line 73 didn't jump to line 74, because the condition on line 73 was never true
74 self.subject = subject
75 if plain_text_content is not None: 75 ↛ 76line 75 didn't jump to line 76, because the condition on line 75 was never true
76 self.add_content(plain_text_content, MimeType.text)
77 if amp_html_content is not None: 77 ↛ 78line 77 didn't jump to line 78, because the condition on line 77 was never true
78 self.add_content(amp_html_content, MimeType.amp)
79 if html_content is not None: 79 ↛ 80line 79 didn't jump to line 80, because the condition on line 79 was never true
80 self.add_content(html_content, MimeType.html)
82 def __str__(self):
83 """A JSON-ready string representation of this Mail object.
85 :returns: A JSON-ready string representation of this Mail object.
86 :rtype: string
87 """
88 return str(self.get())
90 def _ensure_append(self, new_items, append_to, index=0):
91 """Ensure an item is appended to a list or create a new empty list
93 :param new_items: the item(s) to append
94 :type new_items: list(obj)
95 :param append_to: the list on which to append the items
96 :type append_to: list()
97 :param index: index of the list on which to append the items
98 :type index: int
99 """
100 append_to = append_to or []
101 append_to.insert(index, new_items)
102 return append_to
104 def _ensure_insert(self, new_items, insert_to):
105 """Ensure an item is inserted to a list or create a new empty list
107 :param new_items: the item(s) to insert
108 :type new_items: list(obj)
109 :param insert_to: the list on which to insert the items at index 0
110 :type insert_to: list()
111 """
112 insert_to = insert_to or []
113 insert_to.insert(0, new_items)
114 return insert_to
116 def _flatten_dicts(self, dicts):
117 """Flatten a dict
119 :param dicts: Flatten a dict
120 :type dicts: list(dict)
121 """
122 d = dict()
123 list_of_dicts = [d.get() for d in dicts or []]
124 return {k: v for d in list_of_dicts for k, v in d.items()}
126 def _get_or_none(self, from_obj):
127 """Get the JSON representation of the object, else return None
129 :param from_obj: Get the JSON representation of the object,
130 else return None
131 :type from_obj: obj
132 """
133 return from_obj.get() if from_obj is not None else None
135 def _set_emails(
136 self, emails, global_substitutions=None, is_multiple=False, p=0):
137 """Adds emails to the Personalization object
139 :param emails: An Email or list of Email objects
140 :type emails: Email, list(Email)
141 :param global_substitutions: A dict of substitutions for all recipients
142 :type global_substitutions: dict
143 :param is_multiple: Create a new personalization for each recipient
144 :type is_multiple: bool
145 :param p: p is the Personalization object or Personalization object
146 index
147 :type p: Personalization, integer, optional
148 """
149 # Send multiple emails to multiple recipients
150 if is_multiple is True: 150 ↛ 151line 150 didn't jump to line 151, because the condition on line 150 was never true
151 if isinstance(emails, list):
152 for email in emails:
153 personalization = Personalization()
154 personalization.add_email(email)
155 self.add_personalization(personalization)
156 else:
157 personalization = Personalization()
158 personalization.add_email(emails)
159 self.add_personalization(personalization)
160 if global_substitutions is not None:
161 if isinstance(global_substitutions, list):
162 for substitution in global_substitutions:
163 for p in self.personalizations:
164 p.add_substitution(substitution)
165 else:
166 for p in self.personalizations:
167 p.add_substitution(global_substitutions)
168 else:
169 try:
170 personalization = self._personalizations[p]
171 has_internal_personalization = True
172 except IndexError:
173 personalization = Personalization()
174 has_internal_personalization = False
176 if isinstance(emails, list): 176 ↛ 177line 176 didn't jump to line 177, because the condition on line 176 was never true
177 for email in emails:
178 personalization.add_email(email)
179 else:
180 personalization.add_email(emails)
182 if global_substitutions is not None: 182 ↛ 183line 182 didn't jump to line 183, because the condition on line 182 was never true
183 if isinstance(global_substitutions, list):
184 for substitution in global_substitutions:
185 personalization.add_substitution(substitution)
186 else:
187 personalization.add_substitution(global_substitutions)
189 if not has_internal_personalization: 189 ↛ exitline 189 didn't return from function '_set_emails', because the condition on line 189 was never false
190 self.add_personalization(personalization, index=p)
192 @property
193 def personalizations(self):
194 """A list of one or more Personalization objects
196 :rtype: list(Personalization)
197 """
198 return self._personalizations
200 def add_personalization(self, personalization, index=0):
201 """Add a Personalization object
203 :param personalization: Add a Personalization object
204 :type personalization: Personalization
205 :param index: The index where to add the Personalization
206 :type index: int
207 """
208 self._personalizations = self._ensure_append(
209 personalization, self._personalizations, index)
211 @property
212 def to(self):
213 pass
215 @to.setter
216 def to(self, to_emails, global_substitutions=None, is_multiple=False, p=0):
217 """Adds To objects to the Personalization object
219 :param to_emails: The email addresses of all recipients
220 :type to_emails: To, str, tuple, list(str), list(tuple), list(To)
221 :param global_substitutions: A dict of substitutions for all recipients
222 :type global_substitutions: dict
223 :param is_multiple: Create a new personalization for each recipient
224 :type is_multiple: bool
225 :param p: p is the Personalization object or Personalization object
226 index
227 :type p: Personalization, integer, optional
228 """
229 if isinstance(to_emails, list):
230 for email in to_emails:
231 if isinstance(email, str):
232 email = To(email, None)
233 if isinstance(email, tuple):
234 email = To(email[0], email[1])
235 self.add_to(email, global_substitutions, is_multiple, p)
236 else:
237 if isinstance(to_emails, str):
238 to_emails = To(to_emails, None)
239 if isinstance(to_emails, tuple):
240 to_emails = To(to_emails[0], to_emails[1])
241 self.add_to(to_emails, global_substitutions, is_multiple, p)
243 def add_to(
244 self, to_email, global_substitutions=None, is_multiple=False, p=0):
245 """Adds a To object to the Personalization object
247 :param to_email: A To object
248 :type to_email: To, str, tuple, list(str), list(tuple), list(To)
249 :param global_substitutions: A dict of substitutions for all recipients
250 :type global_substitutions: dict
251 :param is_multiple: Create a new personalization for each recipient
252 :type is_multiple: bool
253 :param p: p is the Personalization object or Personalization object
254 index
255 :type p: Personalization, integer, optional
256 """
258 if isinstance(to_email, list): 258 ↛ 259line 258 didn't jump to line 259, because the condition on line 258 was never true
259 for email in to_email:
260 if isinstance(email, str):
261 email = To(email, None)
262 elif isinstance(email, tuple):
263 email = To(email[0], email[1])
264 elif not isinstance(email, Email):
265 raise ValueError(
266 'Please use a To/Cc/Bcc, tuple, or a str for a to_email list.'
267 )
268 self._set_emails(email, global_substitutions, is_multiple, p)
269 else:
270 if isinstance(to_email, str): 270 ↛ 272line 270 didn't jump to line 272, because the condition on line 270 was never false
271 to_email = To(to_email, None)
272 if isinstance(to_email, tuple): 272 ↛ 273line 272 didn't jump to line 273, because the condition on line 272 was never true
273 to_email = To(to_email[0], to_email[1])
274 if isinstance(to_email, Email): 274 ↛ 276line 274 didn't jump to line 276, because the condition on line 274 was never false
275 p = to_email.personalization
276 self._set_emails(to_email, global_substitutions, is_multiple, p)
278 @property
279 def cc(self):
280 pass
282 @cc.setter
283 def cc(self, cc_emails, global_substitutions=None, is_multiple=False, p=0):
284 """Adds Cc objects to the Personalization object
286 :param cc_emails: An Cc or list of Cc objects
287 :type cc_emails: Cc, list(Cc), tuple
288 :param global_substitutions: A dict of substitutions for all recipients
289 :type global_substitutions: dict
290 :param is_multiple: Create a new personalization for each recipient
291 :type is_multiple: bool
292 :param p: p is the Personalization object or Personalization object
293 index
294 :type p: Personalization, integer, optional
295 """
296 if isinstance(cc_emails, list):
297 for email in cc_emails:
298 if isinstance(email, str):
299 email = Cc(email, None)
300 if isinstance(email, tuple):
301 email = Cc(email[0], email[1])
302 self.add_cc(email, global_substitutions, is_multiple, p)
303 else:
304 if isinstance(cc_emails, str):
305 cc_emails = Cc(cc_emails, None)
306 if isinstance(cc_emails, tuple):
307 cc_emails = To(cc_emails[0], cc_emails[1])
308 self.add_cc(cc_emails, global_substitutions, is_multiple, p)
310 def add_cc(
311 self, cc_email, global_substitutions=None, is_multiple=False, p=0):
312 """Adds a Cc object to the Personalization object
314 :param to_emails: An Cc object
315 :type to_emails: Cc
316 :param global_substitutions: A dict of substitutions for all recipients
317 :type global_substitutions: dict
318 :param is_multiple: Create a new personalization for each recipient
319 :type is_multiple: bool
320 :param p: p is the Personalization object or Personalization object
321 index
322 :type p: Personalization, integer, optional
323 """
324 if isinstance(cc_email, str):
325 cc_email = Cc(cc_email, None)
326 if isinstance(cc_email, tuple):
327 cc_email = Cc(cc_email[0], cc_email[1])
328 if isinstance(cc_email, Email):
329 p = cc_email.personalization
330 self._set_emails(
331 cc_email, global_substitutions, is_multiple=is_multiple, p=p)
333 @property
334 def bcc(self):
335 pass
337 @bcc.setter
338 def bcc(
339 self,
340 bcc_emails,
341 global_substitutions=None,
342 is_multiple=False,
343 p=0):
344 """Adds Bcc objects to the Personalization object
346 :param bcc_emails: An Bcc or list of Bcc objects
347 :type bcc_emails: Bcc, list(Bcc), tuple
348 :param global_substitutions: A dict of substitutions for all recipients
349 :type global_substitutions: dict
350 :param is_multiple: Create a new personalization for each recipient
351 :type is_multiple: bool
352 :param p: p is the Personalization object or Personalization object
353 index
354 :type p: Personalization, integer, optional
355 """
356 if isinstance(bcc_emails, list):
357 for email in bcc_emails:
358 if isinstance(email, str):
359 email = Bcc(email, None)
360 if isinstance(email, tuple):
361 email = Bcc(email[0], email[1])
362 self.add_bcc(email, global_substitutions, is_multiple, p)
363 else:
364 if isinstance(bcc_emails, str):
365 bcc_emails = Bcc(bcc_emails, None)
366 if isinstance(bcc_emails, tuple):
367 bcc_emails = Bcc(bcc_emails[0], bcc_emails[1])
368 self.add_bcc(bcc_emails, global_substitutions, is_multiple, p)
370 def add_bcc(
371 self,
372 bcc_email,
373 global_substitutions=None,
374 is_multiple=False,
375 p=0):
376 """Adds a Bcc object to the Personalization object
378 :param to_emails: An Bcc object
379 :type to_emails: Bcc
380 :param global_substitutions: A dict of substitutions for all recipients
381 :type global_substitutions: dict
382 :param is_multiple: Create a new personalization for each recipient
383 :type is_multiple: bool
384 :param p: p is the Personalization object or Personalization object
385 index
386 :type p: Personalization, integer, optional
387 """
388 if isinstance(bcc_email, str):
389 bcc_email = Bcc(bcc_email, None)
390 if isinstance(bcc_email, tuple):
391 bcc_email = Bcc(bcc_email[0], bcc_email[1])
392 if isinstance(bcc_email, Email):
393 p = bcc_email.personalization
394 self._set_emails(
395 bcc_email,
396 global_substitutions,
397 is_multiple=is_multiple,
398 p=p)
400 @property
401 def subject(self):
402 """The global Subject object
404 :rtype: Subject
405 """
406 return self._subject
408 @subject.setter
409 def subject(self, value):
410 """The subject of the email(s)
412 :param value: The subject of the email(s)
413 :type value: Subject, string
414 """
415 if isinstance(value, Subject):
416 if value.personalization is not None:
417 try:
418 personalization = \
419 self._personalizations[value.personalization]
420 has_internal_personalization = True
421 except IndexError:
422 personalization = Personalization()
423 has_internal_personalization = False
424 personalization.subject = value.subject
426 if not has_internal_personalization:
427 self.add_personalization(
428 personalization,
429 index=value.personalization)
430 else:
431 self._subject = value
432 else:
433 self._subject = Subject(value)
435 @property
436 def headers(self):
437 """A list of global Header objects
439 :rtype: list(Header)
440 """
441 return self._headers
443 @property
444 def header(self):
445 pass
447 @header.setter
448 def header(self, headers):
449 """Add headers to the email
451 :param value: A list of Header objects or a dict of header key/values
452 :type value: Header, list(Header), dict
453 """
454 if isinstance(headers, list):
455 for h in headers:
456 self.add_header(h)
457 else:
458 self.add_header(headers)
460 def add_header(self, header):
461 """Add headers to the email globaly or to a specific Personalization
463 :param value: A Header object or a dict of header key/values
464 :type value: Header, dict
465 """
466 if header.personalization is not None:
467 try:
468 personalization = \
469 self._personalizations[header.personalization]
470 has_internal_personalization = True
471 except IndexError:
472 personalization = Personalization()
473 has_internal_personalization = False
474 if isinstance(header, dict):
475 (k, v) = list(header.items())[0]
476 personalization.add_header(Header(k, v))
477 else:
478 personalization.add_header(header)
480 if not has_internal_personalization:
481 self.add_personalization(
482 personalization,
483 index=header.personalization)
484 else:
485 if isinstance(header, dict):
486 (k, v) = list(header.items())[0]
487 self._headers = self._ensure_append(
488 Header(k, v), self._headers)
489 else:
490 self._headers = self._ensure_append(header, self._headers)
492 @property
493 def substitution(self):
494 pass
496 @substitution.setter
497 def substitution(self, substitution):
498 """Add substitutions to the email
500 :param value: Add substitutions to the email
501 :type value: Substitution, list(Substitution)
502 """
503 if isinstance(substitution, list):
504 for s in substitution:
505 self.add_substitution(s)
506 else:
507 self.add_substitution(substitution)
509 def add_substitution(self, substitution):
510 """Add a substitution to the email
512 :param value: Add a substitution to the email
513 :type value: Substitution
514 """
515 if substitution.personalization:
516 try:
517 personalization = \
518 self._personalizations[substitution.personalization]
519 has_internal_personalization = True
520 except IndexError:
521 personalization = Personalization()
522 has_internal_personalization = False
523 personalization.add_substitution(substitution)
525 if not has_internal_personalization:
526 self.add_personalization(
527 personalization, index=substitution.personalization)
528 else:
529 if isinstance(substitution, list):
530 for s in substitution:
531 for p in self.personalizations:
532 p.add_substitution(s)
533 else:
534 for p in self.personalizations:
535 p.add_substitution(substitution)
537 @property
538 def custom_args(self):
539 """A list of global CustomArg objects
541 :rtype: list(CustomArg)
542 """
543 return self._custom_args
545 @property
546 def custom_arg(self):
547 return self._custom_args
549 @custom_arg.setter
550 def custom_arg(self, custom_arg):
551 """Add custom args to the email
553 :param value: A list of CustomArg objects or a dict of custom arg
554 key/values
555 :type value: CustomArg, list(CustomArg), dict
556 """
557 if isinstance(custom_arg, list):
558 for c in custom_arg:
559 self.add_custom_arg(c)
560 else:
561 self.add_custom_arg(custom_arg)
563 def add_custom_arg(self, custom_arg):
564 """Add custom args to the email globaly or to a specific Personalization
566 :param value: A CustomArg object or a dict of custom arg key/values
567 :type value: CustomArg, dict
568 """
569 if custom_arg.personalization is not None:
570 try:
571 personalization = \
572 self._personalizations[custom_arg.personalization]
573 has_internal_personalization = True
574 except IndexError:
575 personalization = Personalization()
576 has_internal_personalization = False
577 if isinstance(custom_arg, dict):
578 (k, v) = list(custom_arg.items())[0]
579 personalization.add_custom_arg(CustomArg(k, v))
580 else:
581 personalization.add_custom_arg(custom_arg)
583 if not has_internal_personalization:
584 self.add_personalization(
585 personalization, index=custom_arg.personalization)
586 else:
587 if isinstance(custom_arg, dict):
588 (k, v) = list(custom_arg.items())[0]
589 self._custom_args = self._ensure_append(
590 CustomArg(k, v), self._custom_args)
591 else:
592 self._custom_args = self._ensure_append(
593 custom_arg, self._custom_args)
595 @property
596 def send_at(self):
597 """The global SendAt object
599 :rtype: SendAt
600 """
601 return self._send_at
603 @send_at.setter
604 def send_at(self, value):
605 """A unix timestamp specifying when your email should
606 be delivered.
608 :param value: A unix timestamp specifying when your email should
609 be delivered.
610 :type value: SendAt, int
611 """
612 if isinstance(value, SendAt):
613 if value.personalization is not None:
614 try:
615 personalization = \
616 self._personalizations[value.personalization]
617 has_internal_personalization = True
618 except IndexError:
619 personalization = Personalization()
620 has_internal_personalization = False
621 personalization.send_at = value.send_at
623 if not has_internal_personalization:
624 self.add_personalization(
625 personalization, index=value.personalization)
626 else:
627 self._send_at = value
628 else:
629 self._send_at = SendAt(value)
631 @property
632 def dynamic_template_data(self):
633 pass
635 @dynamic_template_data.setter
636 def dynamic_template_data(self, value):
637 """Data for a transactional template
639 :param value: Data for a transactional template
640 :type value: DynamicTemplateData, a JSON-serializable structure
641 """
642 if not isinstance(value, DynamicTemplateData): 642 ↛ 644line 642 didn't jump to line 644, because the condition on line 642 was never false
643 value = DynamicTemplateData(value)
644 try:
645 personalization = self._personalizations[value.personalization]
646 has_internal_personalization = True
647 except IndexError:
648 personalization = Personalization()
649 has_internal_personalization = False
650 personalization.dynamic_template_data = value.dynamic_template_data
652 if not has_internal_personalization: 652 ↛ 653line 652 didn't jump to line 653, because the condition on line 652 was never true
653 self.add_personalization(
654 personalization, index=value.personalization)
656 @property
657 def from_email(self):
658 """The email address of the sender
660 :rtype: From
661 """
662 return self._from_email
664 @from_email.setter
665 def from_email(self, value):
666 """The email address of the sender
668 :param value: The email address of the sender
669 :type value: From, str, tuple
670 """
671 if isinstance(value, str): 671 ↛ 673line 671 didn't jump to line 673, because the condition on line 671 was never false
672 value = From(value, None)
673 if isinstance(value, tuple): 673 ↛ 674line 673 didn't jump to line 674, because the condition on line 673 was never true
674 value = From(value[0], value[1])
675 self._from_email = value
677 @property
678 def reply_to(self):
679 """The reply to email address
681 :rtype: ReplyTo
682 """
683 return self._reply_to
685 @reply_to.setter
686 def reply_to(self, value):
687 """The reply to email address
689 :param value: The reply to email address
690 :type value: ReplyTo, str, tuple
691 """
692 if isinstance(value, str):
693 value = ReplyTo(value, None)
694 if isinstance(value, tuple):
695 value = ReplyTo(value[0], value[1])
696 self._reply_to = value
698 @property
699 def contents(self):
700 """The contents of the email
702 :rtype: list(Content)
703 """
704 return self._contents
706 @property
707 def content(self):
708 pass
710 @content.setter
711 def content(self, contents):
712 """The content(s) of the email
714 :param contents: The content(s) of the email
715 :type contents: Content, list(Content)
716 """
717 if isinstance(contents, list):
718 for c in contents:
719 self.add_content(c)
720 else:
721 self.add_content(contents)
723 def add_content(self, content, mime_type=None):
724 """Add content to the email
726 :param contents: Content to be added to the email
727 :type contents: Content
728 :param mime_type: Override the mime type
729 :type mime_type: MimeType, str
730 """
731 if isinstance(content, str):
732 content = Content(mime_type, content)
733 # Content of mime type text/plain must always come first, followed by text/x-amp-html and then text/html
734 if content.mime_type == MimeType.text:
735 self._contents = self._ensure_insert(content, self._contents)
736 elif content.mime_type == MimeType.amp:
737 if self._contents:
738 for _content in self._contents:
739 # this is written in the context that plain text content will always come earlier than the html content
740 if _content.mime_type == MimeType.text:
741 index = 1
742 break
743 elif _content.mime_type == MimeType.html:
744 index = 0
745 break
746 else:
747 index = 0
748 self._contents = self._ensure_append(
749 content, self._contents, index=index)
750 else:
751 if self._contents:
752 index = len(self._contents)
753 else:
754 index = 0
755 self._contents = self._ensure_append(
756 content, self._contents, index=index)
758 @property
759 def attachments(self):
760 """The attachments to this email
762 :rtype: list(Attachment)
763 """
764 return self._attachments
766 @property
767 def attachment(self):
768 pass
770 @attachment.setter
771 def attachment(self, attachment):
772 """Add attachment(s) to this email
774 :param attachment: Add attachment(s) to this email
775 :type attachment: Attachment, list(Attachment)
776 """
777 if isinstance(attachment, list):
778 for a in attachment:
779 self.add_attachment(a)
780 else:
781 self.add_attachment(attachment)
783 def add_attachment(self, attachment):
784 """Add an attachment to this email
786 :param attachment: Add an attachment to this email
787 :type attachment: Attachment
788 """
789 self._attachments = self._ensure_append(attachment, self._attachments)
791 @property
792 def template_id(self):
793 """The transactional template id for this email
795 :rtype: TemplateId
796 """
797 return self._template_id
799 @template_id.setter
800 def template_id(self, value):
801 """The transactional template id for this email
803 :param value: The transactional template id for this email
804 :type value: TemplateId
805 """
806 if isinstance(value, TemplateId): 806 ↛ 807line 806 didn't jump to line 807, because the condition on line 806 was never true
807 self._template_id = value
808 else:
809 self._template_id = TemplateId(value)
811 @property
812 def sections(self):
813 """The block sections of code to be used as substitutions
815 :rtype: Section
816 """
817 return self._sections
819 @property
820 def section(self):
821 pass
823 @section.setter
824 def section(self, section):
825 """The block sections of code to be used as substitutions
827 :rtype: Section, list(Section)
828 """
829 if isinstance(section, list):
830 for h in section:
831 self.add_section(h)
832 else:
833 self.add_section(section)
835 def add_section(self, section):
836 """A block section of code to be used as substitutions
838 :param section: A block section of code to be used as substitutions
839 :type section: Section
840 """
841 self._sections = self._ensure_append(section, self._sections)
843 @property
844 def categories(self):
845 """The categories assigned to this message
847 :rtype: list(Category)
848 """
849 return self._categories
851 @property
852 def category(self):
853 pass
855 @category.setter
856 def category(self, categories):
857 """Add categories assigned to this message
859 :rtype: list(Category)
860 """
861 if isinstance(categories, list):
862 for c in categories:
863 self.add_category(c)
864 else:
865 self.add_category(categories)
867 def add_category(self, category):
868 """Add a category assigned to this message
870 :rtype: Category
871 """
872 self._categories = self._ensure_append(category, self._categories)
874 @property
875 def batch_id(self):
876 """The batch id for this email
878 :rtype: BatchId
879 """
880 return self._batch_id
882 @batch_id.setter
883 def batch_id(self, value):
884 """The batch id for this email
886 :param value: The batch id for this email
887 :type value: BatchId
888 """
889 self._batch_id = value
891 @property
892 def asm(self):
893 """An object specifying unsubscribe behavior.
895 :rtype: Asm
896 """
897 return self._asm
899 @asm.setter
900 def asm(self, value):
901 """An object specifying unsubscribe behavior.
903 :param value: An object specifying unsubscribe behavior.
904 :type value: Asm
905 """
906 self._asm = value
908 @property
909 def ip_pool_name(self):
910 """The IP Pool that you would like to send this email from
912 :rtype: IpPoolName
913 """
914 return self._ip_pool_name
916 @ip_pool_name.setter
917 def ip_pool_name(self, value):
918 """The IP Pool that you would like to send this email from
920 :paran value: The IP Pool that you would like to send this email from
921 :type value: IpPoolName
922 """
923 self._ip_pool_name = value
925 @property
926 def mail_settings(self):
927 """The mail settings for this email
929 :rtype: MailSettings
930 """
931 return self._mail_settings
933 @mail_settings.setter
934 def mail_settings(self, value):
935 """The mail settings for this email
937 :param value: The mail settings for this email
938 :type value: MailSettings
939 """
940 self._mail_settings = value
942 @property
943 def tracking_settings(self):
944 """The tracking settings for this email
946 :rtype: TrackingSettings
947 """
948 return self._tracking_settings
950 @tracking_settings.setter
951 def tracking_settings(self, value):
952 """The tracking settings for this email
954 :param value: The tracking settings for this email
955 :type value: TrackingSettings
956 """
957 self._tracking_settings = value
959 def get(self):
960 """
961 Get a JSON-ready representation of this Mail object.
963 :returns: This Mail object, ready for use in a request body.
964 :rtype: dict
965 """
966 mail = {
967 'from': self._get_or_none(self.from_email),
968 'subject': self._get_or_none(self.subject),
969 'personalizations': [p.get() for p in self.personalizations or []],
970 'content': [c.get() for c in self.contents or []],
971 'attachments': [a.get() for a in self.attachments or []],
972 'template_id': self._get_or_none(self.template_id),
973 'sections': self._flatten_dicts(self.sections),
974 'headers': self._flatten_dicts(self.headers),
975 'categories': [c.get() for c in self.categories or []],
976 'custom_args': self._flatten_dicts(self.custom_args),
977 'send_at': self._get_or_none(self.send_at),
978 'batch_id': self._get_or_none(self.batch_id),
979 'asm': self._get_or_none(self.asm),
980 'ip_pool_name': self._get_or_none(self.ip_pool_name),
981 'mail_settings': self._get_or_none(self.mail_settings),
982 'tracking_settings': self._get_or_none(self.tracking_settings),
983 'reply_to': self._get_or_none(self.reply_to),
984 }
986 return {key: value for key, value in mail.items()
987 if value is not None and value != [] and value != {}}
989 @classmethod
990 def from_EmailMessage(cls, message):
991 """Create a Mail object from an instance of
992 email.message.EmailMessage.
994 :type message: email.message.EmailMessage
995 :rtype: Mail
996 """
997 mail = cls(
998 from_email=Email(message.get('From')),
999 subject=message.get('Subject'),
1000 to_emails=Email(message.get('To')),
1001 )
1002 try:
1003 body = message.get_content()
1004 except AttributeError:
1005 # Python2
1006 body = message.get_payload()
1007 mail.add_content(Content(
1008 message.get_content_type(),
1009 body.strip()
1010 ))
1011 for k, v in message.items():
1012 mail.add_header(Header(k, v))
1013 return mail