def construct(cls, raw_headers=None, from_email=None, to=None, cc=None, subject=None, headers=None, text=None, text_charset='utf-8', html=None, html_charset='utf-8', attachments=None): """ Returns a new AnymailInboundMessage constructed from params. This is designed to handle the sorts of email fields typically present in ESP parsed inbound messages. (It's not a generalized MIME message constructor.) :param raw_headers: {str|None} base (or complete) message headers as a single string :param from_email: {str|None} value for From header :param to: {str|None} value for To header :param cc: {str|None} value for Cc header :param subject: {str|None} value for Subject header :param headers: {sequence[(str, str)]|mapping|None} additional headers :param text: {str|None} plaintext body :param text_charset: {str} charset of plaintext body; default utf-8 :param html: {str|None} html body :param html_charset: {str} charset of html body; default utf-8 :param attachments: {list[MIMEBase]|None} as returned by construct_attachment :return: {AnymailInboundMessage} """ if raw_headers is not None: msg = HeaderParser(cls, policy=accurate_header_unfolding_policy).parsestr(raw_headers) msg.set_payload(None) # headersonly forces an empty string payload, which breaks things later else: msg = cls() if from_email is not None: del msg['From'] # override raw_headers value, if any msg['From'] = from_email if to is not None: del msg['To'] msg['To'] = to if cc is not None: del msg['Cc'] msg['Cc'] = cc if subject is not None: del msg['Subject'] msg['Subject'] = subject if headers is not None: try: header_items = headers.items() # mapping except AttributeError: header_items = headers # sequence of (key, value) for name, value in header_items: msg.add_header(name, value) # For simplicity, we always build a MIME structure that could support plaintext/html # alternative bodies, inline attachments for the body(ies), and message attachments. # This may be overkill for simpler messages, but the structure is never incorrect. del msg['MIME-Version'] # override raw_headers values, if any del msg['Content-Type'] msg['MIME-Version'] = '1.0' msg['Content-Type'] = 'multipart/mixed' related = cls() # container for alternative bodies and inline attachments related['Content-Type'] = 'multipart/related' msg.attach(related) alternatives = cls() # container for text and html bodies alternatives['Content-Type'] = 'multipart/alternative' related.attach(alternatives) if text is not None: part = cls() part['Content-Type'] = 'text/plain' part.set_payload(text, charset=text_charset) alternatives.attach(part) if html is not None: part = cls() part['Content-Type'] = 'text/html' part.set_payload(html, charset=html_charset) alternatives.attach(part) if attachments is not None: for attachment in attachments: if attachment.is_inline_attachment(): related.attach(attachment) else: msg.attach(attachment) return msg