Source code for eletter.core

from datetime import datetime
from email.message import EmailMessage
from typing import Iterable, Mapping, Optional, Union
from mailbits import ContentType
from .classes import Attachment, HTMLBody, MailItem, TextBody
from .util import AddressOrGroup, SingleAddress


[docs]def compose( *, subject: str, to: Iterable[AddressOrGroup], from_: Optional[Union[AddressOrGroup, Iterable[AddressOrGroup]]] = None, text: Optional[str] = None, html: Optional[str] = None, cc: Optional[Iterable[AddressOrGroup]] = None, bcc: Optional[Iterable[AddressOrGroup]] = None, reply_to: Optional[Union[AddressOrGroup, Iterable[AddressOrGroup]]] = None, sender: Optional[SingleAddress] = None, date: Optional[datetime] = None, headers: Optional[Mapping[str, Union[str, Iterable[str]]]] = None, attachments: Optional[Iterable[Attachment]] = None, ) -> EmailMessage: """ Construct an `~email.message.EmailMessage` instance from a subject, :mailheader:`From` address, :mailheader:`To` addresses, and a plain text and/or HTML body, optionally accompanied by attachments and other headers. All parameters other than ``subject``, ``to``, and at least one of ``text`` and ``html`` are optional. :param str subject: The e-mail's :mailheader:`Subject` line :param to: The e-mail's :mailheader:`To` line :type to: iterable of addresses :param from_: The e-mail's :mailheader:`From` line. Note that this argument is spelled with an underscore, as "``from``" is a keyword in Python. :type from_: address or iterable of addresses :param str text: The contents of a :mimetype:`text/plain` body for the e-mail. At least one of ``text`` and ``html`` must be specified. :param str html: The contents of a :mimetype:`text/html` body for the e-mail. At least one of ``text`` and ``html`` must be specified. :param cc: The e-mail's :mailheader:`CC` line :type cc: iterable of addresses :param bcc: The e-mail's :mailheader:`BCC` line :type bcc: iterable of addresses :param reply_to: The e-mail's :mailheader:`Reply-To` line :type reply_to: address or iterable of addresses :param address sender: The e-mail's :mailheader:`Sender` line. The address must be a string or `Address`, not a `Group`. :param datetime date: The e-mail's :mailheader:`Date` line :param attachments: A collection of :ref:`attachments <attachments>` to append to the e-mail :type attachments: iterable of attachments :param mapping headers: A collection of additional headers to add to the e-mail. A header value may be either a single string or an iterable of strings to add multiple headers with the same name. If you wish to set an otherwise-unsupported address header like :mailheader:`Resent-From` to a list of addresses, use the `format_addresses()` function to first convert the addresses to a string. :rtype: email.message.EmailMessage :raises ValueError: if neither ``text`` nor ``html`` is set """ msg: Optional[MailItem] = None if text is not None: msg = TextBody(text) if html is not None: if msg is None: msg = HTMLBody(html) else: msg |= HTMLBody(html) if msg is None: raise ValueError("At least one of text and html must be non-None") if attachments is not None: for a in attachments: msg &= a return msg.compose( subject=subject, from_=from_, to=to, cc=cc, bcc=bcc, reply_to=reply_to, sender=sender, date=date, headers=headers, )
[docs]def assemble_content_type(maintype: str, subtype: str, **params: str) -> str: """ Construct a :mailheader:`Content-Type` string from a maintype, subtype, and some number of parameters :raises ValueError: if ``f"{maintype}/{subtype}"`` is an invalid :mailheader:`Content-Type` """ return str(ContentType(maintype, subtype, params))
[docs]def reply_quote(s: str, prefix: str = "> ") -> str: """ Quote__ a text following the *de facto* standard for replying to an e-mail; that is, prefix each line of the text with ``"> "`` (or a custom prefix), and if a line already starts with the prefix, omit any trailing whitespace from the newly-added prefix (so ``"> already quoted"`` becomes ``">> already quoted"``). If the resulting string does not end with a newline, one is added. The empty string is treated as a single line. __ https://en.wikipedia.org/wiki/Usenet_quoting """ s2 = "" for ln in (s or "\n").splitlines(True): if ln.startswith(prefix): s2 += prefix.rstrip() + ln else: s2 += prefix + ln if not s2.endswith(("\n", "\r")): s2 += "\n" return s2