diff options
Diffstat (limited to '.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail.py')
-rw-r--r-- | .venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail.py | 1041 |
1 files changed, 1041 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail.py b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail.py new file mode 100644 index 00000000..2472ad7d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/sendgrid/helpers/mail/mail.py @@ -0,0 +1,1041 @@ +"""Twilio SendGrid v3/mail/send response body builder""" +from .bcc_email import Bcc +from .cc_email import Cc +from .content import Content +from .custom_arg import CustomArg +from .dynamic_template_data import DynamicTemplateData +from .email import Email +from .from_email import From +from .header import Header +from .mime_type import MimeType +from .personalization import Personalization +from .reply_to import ReplyTo +from .send_at import SendAt +from .subject import Subject +from .substitution import Substitution +from .template_id import TemplateId +from .to_email import To + + +class Mail(object): + """Creates the response body for v3/mail/send""" + + def __init__( + self, + from_email=None, + to_emails=None, + subject=None, + plain_text_content=None, + html_content=None, + amp_html_content=None, + global_substitutions=None, + is_multiple=False): + """ + Creates the response body for a v3/mail/send API call + + :param from_email: The email address of the sender + :type from_email: From, tuple, optional + :param subject: The subject of the email + :type subject: Subject, optional + :param to_emails: The email address of the recipient + :type to_emails: To, str, tuple, list(str), list(tuple), + list(To), optional + :param plain_text_content: The plain text body of the email + :type plain_text_content: string, optional + :param html_content: The html body of the email + :type html_content: string, optional + :param amp_html_content: The amp-html body of the email + :type amp_html_content: string, optional + """ + self._attachments = None + self._categories = None + self._contents = None + self._custom_args = None + self._headers = None + self._personalizations = [] + self._sections = None + self._asm = None + self._batch_id = None + self._from_email = None + self._ip_pool_name = None + self._mail_settings = None + self._reply_to = None + self._reply_to_list = None + self._send_at = None + self._subject = None + self._template_id = None + self._tracking_settings = None + + # Minimum required data to send a single email + if from_email is not None: + self.from_email = from_email + if to_emails is not None: + self.add_to(to_emails, global_substitutions, is_multiple) + if subject is not None: + self.subject = subject + if plain_text_content is not None: + self.add_content(plain_text_content, MimeType.text) + if amp_html_content is not None: + self.add_content(amp_html_content, MimeType.amp) + if html_content is not None: + self.add_content(html_content, MimeType.html) + + def __str__(self): + """A JSON-ready string representation of this Mail object. + + :returns: A JSON-ready string representation of this Mail object. + :rtype: string + """ + return str(self.get()) + + def _ensure_append(self, new_items, append_to, index=0): + """Ensure an item is appended to a list or create a new empty list + + :param new_items: the item(s) to append + :type new_items: list(obj) + :param append_to: the list on which to append the items + :type append_to: list() + :param index: index of the list on which to append the items + :type index: int + """ + append_to = append_to or [] + append_to.insert(index, new_items) + return append_to + + def _ensure_insert(self, new_items, insert_to): + """Ensure an item is inserted to a list or create a new empty list + + :param new_items: the item(s) to insert + :type new_items: list(obj) + :param insert_to: the list on which to insert the items at index 0 + :type insert_to: list() + """ + insert_to = insert_to or [] + insert_to.insert(0, new_items) + return insert_to + + def _flatten_dicts(self, dicts): + """Flatten a dict + + :param dicts: Flatten a dict + :type dicts: list(dict) + """ + d = dict() + list_of_dicts = [d.get() for d in dicts or []] + return {k: v for d in list_of_dicts for k, v in d.items()} + + def _get_or_none(self, from_obj): + """Get the JSON representation of the object, else return None + + :param from_obj: Get the JSON representation of the object, + else return None + :type from_obj: obj + """ + return from_obj.get() if from_obj is not None else None + + def _set_emails( + self, emails, global_substitutions=None, is_multiple=False, p=0): + """Adds emails to the Personalization object + + :param emails: An Email or list of Email objects + :type emails: Email, list(Email) + :param global_substitutions: A dict of substitutions for all recipients + :type global_substitutions: dict + :param is_multiple: Create a new personalization for each recipient + :type is_multiple: bool + :param p: p is the Personalization object or Personalization object + index + :type p: Personalization, integer, optional + """ + # Send multiple emails to multiple recipients + if is_multiple is True: + if isinstance(emails, list): + for email in emails: + personalization = Personalization() + personalization.add_email(email) + self.add_personalization(personalization) + else: + personalization = Personalization() + personalization.add_email(emails) + self.add_personalization(personalization) + if global_substitutions is not None: + if isinstance(global_substitutions, list): + for substitution in global_substitutions: + for p in self.personalizations: + p.add_substitution(substitution) + else: + for p in self.personalizations: + p.add_substitution(global_substitutions) + else: + try: + personalization = self._personalizations[p] + has_internal_personalization = True + except IndexError: + personalization = Personalization() + has_internal_personalization = False + + if isinstance(emails, list): + for email in emails: + personalization.add_email(email) + else: + personalization.add_email(emails) + + if global_substitutions is not None: + if isinstance(global_substitutions, list): + for substitution in global_substitutions: + personalization.add_substitution(substitution) + else: + personalization.add_substitution(global_substitutions) + + if not has_internal_personalization: + self.add_personalization(personalization, index=p) + + @property + def personalizations(self): + """A list of one or more Personalization objects + + :rtype: list(Personalization) + """ + return self._personalizations + + def add_personalization(self, personalization, index=0): + """Add a Personalization object + + :param personalization: Add a Personalization object + :type personalization: Personalization + :param index: The index where to add the Personalization + :type index: int + """ + self._personalizations = self._ensure_append( + personalization, self._personalizations, index) + + @property + def to(self): + pass + + @to.setter + def to(self, to_emails, global_substitutions=None, is_multiple=False, p=0): + """Adds To objects to the Personalization object + + :param to_emails: The email addresses of all recipients + :type to_emails: To, str, tuple, list(str), list(tuple), list(To) + :param global_substitutions: A dict of substitutions for all recipients + :type global_substitutions: dict + :param is_multiple: Create a new personalization for each recipient + :type is_multiple: bool + :param p: p is the Personalization object or Personalization object + index + :type p: Personalization, integer, optional + """ + if isinstance(to_emails, list): + for email in to_emails: + if isinstance(email, str): + email = To(email, None) + if isinstance(email, tuple): + email = To(email[0], email[1]) + self.add_to(email, global_substitutions, is_multiple, p) + else: + if isinstance(to_emails, str): + to_emails = To(to_emails, None) + if isinstance(to_emails, tuple): + to_emails = To(to_emails[0], to_emails[1]) + self.add_to(to_emails, global_substitutions, is_multiple, p) + + def add_to( + self, to_email, global_substitutions=None, is_multiple=False, p=0): + """Adds a To object to the Personalization object + + :param to_email: A To object + :type to_email: To, str, tuple, list(str), list(tuple), list(To) + :param global_substitutions: A dict of substitutions for all recipients + :type global_substitutions: dict + :param is_multiple: Create a new personalization for each recipient + :type is_multiple: bool + :param p: p is the Personalization object or Personalization object + index + :type p: Personalization, integer, optional + """ + + if isinstance(to_email, list): + for email in to_email: + if isinstance(email, str): + email = To(email, None) + elif isinstance(email, tuple): + email = To(email[0], email[1]) + elif not isinstance(email, Email): + raise ValueError( + 'Please use a To/Cc/Bcc, tuple, or a str for a to_email list.' + ) + self._set_emails(email, global_substitutions, is_multiple, p) + else: + if isinstance(to_email, str): + to_email = To(to_email, None) + if isinstance(to_email, tuple): + to_email = To(to_email[0], to_email[1]) + if isinstance(to_email, Email): + p = to_email.personalization + self._set_emails(to_email, global_substitutions, is_multiple, p) + + @property + def cc(self): + pass + + @cc.setter + def cc(self, cc_emails, global_substitutions=None, is_multiple=False, p=0): + """Adds Cc objects to the Personalization object + + :param cc_emails: An Cc or list of Cc objects + :type cc_emails: Cc, list(Cc), tuple + :param global_substitutions: A dict of substitutions for all recipients + :type global_substitutions: dict + :param is_multiple: Create a new personalization for each recipient + :type is_multiple: bool + :param p: p is the Personalization object or Personalization object + index + :type p: Personalization, integer, optional + """ + if isinstance(cc_emails, list): + for email in cc_emails: + if isinstance(email, str): + email = Cc(email, None) + if isinstance(email, tuple): + email = Cc(email[0], email[1]) + self.add_cc(email, global_substitutions, is_multiple, p) + else: + if isinstance(cc_emails, str): + cc_emails = Cc(cc_emails, None) + if isinstance(cc_emails, tuple): + cc_emails = To(cc_emails[0], cc_emails[1]) + self.add_cc(cc_emails, global_substitutions, is_multiple, p) + + def add_cc( + self, cc_email, global_substitutions=None, is_multiple=False, p=0): + """Adds a Cc object to the Personalization object + + :param to_emails: An Cc object + :type to_emails: Cc + :param global_substitutions: A dict of substitutions for all recipients + :type global_substitutions: dict + :param is_multiple: Create a new personalization for each recipient + :type is_multiple: bool + :param p: p is the Personalization object or Personalization object + index + :type p: Personalization, integer, optional + """ + if isinstance(cc_email, str): + cc_email = Cc(cc_email, None) + if isinstance(cc_email, tuple): + cc_email = Cc(cc_email[0], cc_email[1]) + if isinstance(cc_email, Email): + p = cc_email.personalization + self._set_emails( + cc_email, global_substitutions, is_multiple=is_multiple, p=p) + + @property + def bcc(self): + pass + + @bcc.setter + def bcc( + self, + bcc_emails, + global_substitutions=None, + is_multiple=False, + p=0): + """Adds Bcc objects to the Personalization object + + :param bcc_emails: An Bcc or list of Bcc objects + :type bcc_emails: Bcc, list(Bcc), tuple + :param global_substitutions: A dict of substitutions for all recipients + :type global_substitutions: dict + :param is_multiple: Create a new personalization for each recipient + :type is_multiple: bool + :param p: p is the Personalization object or Personalization object + index + :type p: Personalization, integer, optional + """ + if isinstance(bcc_emails, list): + for email in bcc_emails: + if isinstance(email, str): + email = Bcc(email, None) + if isinstance(email, tuple): + email = Bcc(email[0], email[1]) + self.add_bcc(email, global_substitutions, is_multiple, p) + else: + if isinstance(bcc_emails, str): + bcc_emails = Bcc(bcc_emails, None) + if isinstance(bcc_emails, tuple): + bcc_emails = Bcc(bcc_emails[0], bcc_emails[1]) + self.add_bcc(bcc_emails, global_substitutions, is_multiple, p) + + def add_bcc( + self, + bcc_email, + global_substitutions=None, + is_multiple=False, + p=0): + """Adds a Bcc object to the Personalization object + + :param to_emails: An Bcc object + :type to_emails: Bcc + :param global_substitutions: A dict of substitutions for all recipients + :type global_substitutions: dict + :param is_multiple: Create a new personalization for each recipient + :type is_multiple: bool + :param p: p is the Personalization object or Personalization object + index + :type p: Personalization, integer, optional + """ + if isinstance(bcc_email, str): + bcc_email = Bcc(bcc_email, None) + if isinstance(bcc_email, tuple): + bcc_email = Bcc(bcc_email[0], bcc_email[1]) + if isinstance(bcc_email, Email): + p = bcc_email.personalization + self._set_emails( + bcc_email, + global_substitutions, + is_multiple=is_multiple, + p=p) + + @property + def subject(self): + """The global Subject object + + :rtype: Subject + """ + return self._subject + + @subject.setter + def subject(self, value): + """The subject of the email(s) + + :param value: The subject of the email(s) + :type value: Subject, string + """ + if isinstance(value, Subject): + if value.personalization is not None: + try: + personalization = \ + self._personalizations[value.personalization] + has_internal_personalization = True + except IndexError: + personalization = Personalization() + has_internal_personalization = False + personalization.subject = value.subject + + if not has_internal_personalization: + self.add_personalization( + personalization, + index=value.personalization) + else: + self._subject = value + else: + self._subject = Subject(value) + + @property + def headers(self): + """A list of global Header objects + + :rtype: list(Header) + """ + return self._headers + + @property + def header(self): + pass + + @header.setter + def header(self, headers): + """Add headers to the email + + :param value: A list of Header objects or a dict of header key/values + :type value: Header, list(Header), dict + """ + if isinstance(headers, list): + for h in headers: + self.add_header(h) + else: + self.add_header(headers) + + def add_header(self, header): + """Add headers to the email globaly or to a specific Personalization + + :param value: A Header object or a dict of header key/values + :type value: Header, dict + """ + if header.personalization is not None: + try: + personalization = \ + self._personalizations[header.personalization] + has_internal_personalization = True + except IndexError: + personalization = Personalization() + has_internal_personalization = False + if isinstance(header, dict): + (k, v) = list(header.items())[0] + personalization.add_header(Header(k, v)) + else: + personalization.add_header(header) + + if not has_internal_personalization: + self.add_personalization( + personalization, + index=header.personalization) + else: + if isinstance(header, dict): + (k, v) = list(header.items())[0] + self._headers = self._ensure_append( + Header(k, v), self._headers) + else: + self._headers = self._ensure_append(header, self._headers) + + @property + def substitution(self): + pass + + @substitution.setter + def substitution(self, substitution): + """Add substitutions to the email + + :param value: Add substitutions to the email + :type value: Substitution, list(Substitution) + """ + if isinstance(substitution, list): + for s in substitution: + self.add_substitution(s) + else: + self.add_substitution(substitution) + + def add_substitution(self, substitution): + """Add a substitution to the email + + :param value: Add a substitution to the email + :type value: Substitution + """ + if substitution.personalization: + try: + personalization = \ + self._personalizations[substitution.personalization] + has_internal_personalization = True + except IndexError: + personalization = Personalization() + has_internal_personalization = False + personalization.add_substitution(substitution) + + if not has_internal_personalization: + self.add_personalization( + personalization, index=substitution.personalization) + else: + if isinstance(substitution, list): + for s in substitution: + for p in self.personalizations: + p.add_substitution(s) + else: + for p in self.personalizations: + p.add_substitution(substitution) + + @property + def custom_args(self): + """A list of global CustomArg objects + + :rtype: list(CustomArg) + """ + return self._custom_args + + @property + def custom_arg(self): + return self._custom_args + + @custom_arg.setter + def custom_arg(self, custom_arg): + """Add custom args to the email + + :param value: A list of CustomArg objects or a dict of custom arg + key/values + :type value: CustomArg, list(CustomArg), dict + """ + if isinstance(custom_arg, list): + for c in custom_arg: + self.add_custom_arg(c) + else: + self.add_custom_arg(custom_arg) + + def add_custom_arg(self, custom_arg): + """Add custom args to the email globaly or to a specific Personalization + + :param value: A CustomArg object or a dict of custom arg key/values + :type value: CustomArg, dict + """ + if custom_arg.personalization is not None: + try: + personalization = \ + self._personalizations[custom_arg.personalization] + has_internal_personalization = True + except IndexError: + personalization = Personalization() + has_internal_personalization = False + if isinstance(custom_arg, dict): + (k, v) = list(custom_arg.items())[0] + personalization.add_custom_arg(CustomArg(k, v)) + else: + personalization.add_custom_arg(custom_arg) + + if not has_internal_personalization: + self.add_personalization( + personalization, index=custom_arg.personalization) + else: + if isinstance(custom_arg, dict): + (k, v) = list(custom_arg.items())[0] + self._custom_args = self._ensure_append( + CustomArg(k, v), self._custom_args) + else: + self._custom_args = self._ensure_append( + custom_arg, self._custom_args) + + @property + def send_at(self): + """The global SendAt object + + :rtype: SendAt + """ + return self._send_at + + @send_at.setter + def send_at(self, value): + """A unix timestamp specifying when your email should + be delivered. + + :param value: A unix timestamp specifying when your email should + be delivered. + :type value: SendAt, int + """ + if isinstance(value, SendAt): + if value.personalization is not None: + try: + personalization = \ + self._personalizations[value.personalization] + has_internal_personalization = True + except IndexError: + personalization = Personalization() + has_internal_personalization = False + personalization.send_at = value.send_at + + if not has_internal_personalization: + self.add_personalization( + personalization, index=value.personalization) + else: + self._send_at = value + else: + self._send_at = SendAt(value) + + @property + def dynamic_template_data(self): + pass + + @dynamic_template_data.setter + def dynamic_template_data(self, value): + """Data for a transactional template + + :param value: Data for a transactional template + :type value: DynamicTemplateData, a JSON-serializable structure + """ + if not isinstance(value, DynamicTemplateData): + value = DynamicTemplateData(value) + try: + personalization = self._personalizations[value.personalization] + has_internal_personalization = True + except IndexError: + personalization = Personalization() + has_internal_personalization = False + personalization.dynamic_template_data = value.dynamic_template_data + + if not has_internal_personalization: + self.add_personalization( + personalization, index=value.personalization) + + @property + def from_email(self): + """The email address of the sender + + :rtype: From + """ + return self._from_email + + @from_email.setter + def from_email(self, value): + """The email address of the sender + + :param value: The email address of the sender + :type value: From, str, tuple + """ + if isinstance(value, str): + value = From(value, None) + if isinstance(value, tuple): + value = From(value[0], value[1]) + self._from_email = value + + @property + def reply_to(self): + """The reply to email address + + :rtype: ReplyTo + """ + return self._reply_to + + @reply_to.setter + def reply_to(self, value): + """The reply to email address + + :param value: The reply to email address + :type value: ReplyTo, str, tuple + """ + if isinstance(value, str): + value = ReplyTo(value, None) + if isinstance(value, tuple): + value = ReplyTo(value[0], value[1]) + self._reply_to = value + + @property + def reply_to_list(self): + """A list of ReplyTo email addresses + + :rtype: list(ReplyTo), tuple + """ + return self._reply_to_list + + @reply_to_list.setter + def reply_to_list(self, value): + """A list of ReplyTo email addresses + + :param value: A list of ReplyTo email addresses + :type value: list(ReplyTo), tuple + """ + if isinstance(value, list): + for reply in value: + if isinstance(reply, ReplyTo): + if not isinstance(reply.email, str): + raise ValueError('You must provide an email for each entry in a reply_to_list') + else: + raise ValueError( + 'Please use a list of ReplyTos for a reply_to_list.' + ) + self._reply_to_list = value + + @property + def contents(self): + """The contents of the email + + :rtype: list(Content) + """ + return self._contents + + @property + def content(self): + pass + + @content.setter + def content(self, contents): + """The content(s) of the email + + :param contents: The content(s) of the email + :type contents: Content, list(Content) + """ + if isinstance(contents, list): + for c in contents: + self.add_content(c) + else: + self.add_content(contents) + + def add_content(self, content, mime_type=None): + """Add content to the email + + :param contents: Content to be added to the email + :type contents: Content + :param mime_type: Override the mime type + :type mime_type: MimeType, str + """ + if isinstance(content, str): + content = Content(mime_type, content) + # Content of mime type text/plain must always come first, followed by text/x-amp-html and then text/html + if content.mime_type == MimeType.text: + self._contents = self._ensure_insert(content, self._contents) + elif content.mime_type == MimeType.amp: + if self._contents: + for _content in self._contents: + # this is written in the context that plain text content will always come earlier than the html content + if _content.mime_type == MimeType.text: + index = 1 + break + elif _content.mime_type == MimeType.html: + index = 0 + break + else: + index = 0 + self._contents = self._ensure_append( + content, self._contents, index=index) + else: + if self._contents: + index = len(self._contents) + else: + index = 0 + self._contents = self._ensure_append( + content, self._contents, index=index) + + @property + def attachments(self): + """The attachments to this email + + :rtype: list(Attachment) + """ + return self._attachments + + @property + def attachment(self): + pass + + @attachment.setter + def attachment(self, attachment): + """Add attachment(s) to this email + + :param attachment: Add attachment(s) to this email + :type attachment: Attachment, list(Attachment) + """ + if isinstance(attachment, list): + for a in attachment: + self.add_attachment(a) + else: + self.add_attachment(attachment) + + def add_attachment(self, attachment): + """Add an attachment to this email + + :param attachment: Add an attachment to this email + :type attachment: Attachment + """ + self._attachments = self._ensure_append(attachment, self._attachments) + + @property + def template_id(self): + """The transactional template id for this email + + :rtype: TemplateId + """ + return self._template_id + + @template_id.setter + def template_id(self, value): + """The transactional template id for this email + + :param value: The transactional template id for this email + :type value: TemplateId + """ + if isinstance(value, TemplateId): + self._template_id = value + else: + self._template_id = TemplateId(value) + + @property + def sections(self): + """The block sections of code to be used as substitutions + + :rtype: Section + """ + return self._sections + + @property + def section(self): + pass + + @section.setter + def section(self, section): + """The block sections of code to be used as substitutions + + :rtype: Section, list(Section) + """ + if isinstance(section, list): + for h in section: + self.add_section(h) + else: + self.add_section(section) + + def add_section(self, section): + """A block section of code to be used as substitutions + + :param section: A block section of code to be used as substitutions + :type section: Section + """ + self._sections = self._ensure_append(section, self._sections) + + @property + def categories(self): + """The categories assigned to this message + + :rtype: list(Category) + """ + return self._categories + + @property + def category(self): + pass + + @category.setter + def category(self, categories): + """Add categories assigned to this message + + :rtype: list(Category) + """ + if isinstance(categories, list): + for c in categories: + self.add_category(c) + else: + self.add_category(categories) + + def add_category(self, category): + """Add a category assigned to this message + + :rtype: Category + """ + self._categories = self._ensure_append(category, self._categories) + + @property + def batch_id(self): + """The batch id for this email + + :rtype: BatchId + """ + return self._batch_id + + @batch_id.setter + def batch_id(self, value): + """The batch id for this email + + :param value: The batch id for this email + :type value: BatchId + """ + self._batch_id = value + + @property + def asm(self): + """An object specifying unsubscribe behavior. + + :rtype: Asm + """ + return self._asm + + @asm.setter + def asm(self, value): + """An object specifying unsubscribe behavior. + + :param value: An object specifying unsubscribe behavior. + :type value: Asm + """ + self._asm = value + + @property + def ip_pool_name(self): + """The IP Pool that you would like to send this email from + + :rtype: IpPoolName + """ + return self._ip_pool_name + + @ip_pool_name.setter + def ip_pool_name(self, value): + """The IP Pool that you would like to send this email from + + :paran value: The IP Pool that you would like to send this email from + :type value: IpPoolName + """ + self._ip_pool_name = value + + @property + def mail_settings(self): + """The mail settings for this email + + :rtype: MailSettings + """ + return self._mail_settings + + @mail_settings.setter + def mail_settings(self, value): + """The mail settings for this email + + :param value: The mail settings for this email + :type value: MailSettings + """ + self._mail_settings = value + + @property + def tracking_settings(self): + """The tracking settings for this email + + :rtype: TrackingSettings + """ + return self._tracking_settings + + @tracking_settings.setter + def tracking_settings(self, value): + """The tracking settings for this email + + :param value: The tracking settings for this email + :type value: TrackingSettings + """ + self._tracking_settings = value + + def get(self): + """ + Get a JSON-ready representation of this Mail object. + + :returns: This Mail object, ready for use in a request body. + :rtype: dict + """ + mail = { + 'from': self._get_or_none(self.from_email), + 'subject': self._get_or_none(self.subject), + 'personalizations': [p.get() for p in self.personalizations or []], + 'content': [c.get() for c in self.contents or []], + 'attachments': [a.get() for a in self.attachments or []], + 'template_id': self._get_or_none(self.template_id), + 'sections': self._flatten_dicts(self.sections), + 'headers': self._flatten_dicts(self.headers), + 'categories': [c.get() for c in self.categories or []], + 'custom_args': self._flatten_dicts(self.custom_args), + 'send_at': self._get_or_none(self.send_at), + 'batch_id': self._get_or_none(self.batch_id), + 'asm': self._get_or_none(self.asm), + 'ip_pool_name': self._get_or_none(self.ip_pool_name), + 'mail_settings': self._get_or_none(self.mail_settings), + 'tracking_settings': self._get_or_none(self.tracking_settings), + 'reply_to': self._get_or_none(self.reply_to), + 'reply_to_list': [r.get() for r in self.reply_to_list or []], + } + + return {key: value for key, value in mail.items() + if value is not None and value != [] and value != {}} + + @classmethod + def from_EmailMessage(cls, message): + """Create a Mail object from an instance of + email.message.EmailMessage. + + :type message: email.message.EmailMessage + :rtype: Mail + """ + mail = cls( + from_email=Email(message.get('From')), + subject=message.get('Subject'), + to_emails=Email(message.get('To')), + ) + try: + body = message.get_content() + except AttributeError: + # Python2 + body = message.get_payload() + mail.add_content(Content( + message.get_content_type(), + body.strip() + )) + for k, v in message.items(): + mail.add_header(Header(k, v)) + return mail |