API
The compose() Function
- eletter.compose(*, to: Iterable[str | Address | Group], from_: str | Address | Group | Iterable[str | Address | Group] | None = None, subject: str | None = None, text: str | None = None, html: str | None = None, cc: Iterable[str | Address | Group] | None = None, bcc: Iterable[str | Address | Group] | None = None, reply_to: str | Address | Group | Iterable[str | Address | Group] | None = None, sender: str | Address | None = None, date: datetime | None = None, headers: Mapping[str, str | Iterable[str]] | None = None, attachments: Iterable[Attachment] | None = None) EmailMessage[source]
Construct an
EmailMessageinstance from a subject, From address, To addresses, and a plain text and/or HTML body, optionally accompanied by attachments and other headers.All parameters other than
toand at least one oftextandhtmlare optional.Changed in version 0.2.0:
from_andreply_tomay now be passed lists of addresses.Changed in version 0.4.0:
from_may now beNoneor omitted.Changed in version 0.4.0: All arguments are now keyword-only.
Changed in version 0.5.0:
subjectmay now beNoneor omitted.- Parameters:
subject (str) – The e-mail’s Subject line
to (iterable of addresses) – The e-mail’s To line
from_ (address or iterable of addresses) – The e-mail’s From line. Note that this argument is spelled with an underscore, as “
from” is a keyword in Python.text (str) – The contents of a text/plain body for the e-mail. At least one of
textandhtmlmust be specified.html (str) – The contents of a text/html body for the e-mail. At least one of
textandhtmlmust be specified.cc (iterable of addresses) – The e-mail’s CC line
bcc (iterable of addresses) – The e-mail’s BCC line
reply_to (address or iterable of addresses) – The e-mail’s Reply-To line
sender (address) – The e-mail’s Sender line. The address must be a string or
Address, not aGroup.date (datetime) – The e-mail’s Date line
attachments (iterable of attachments) – A collection of attachments to append to the e-mail
headers (mapping) – 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 Resent-From to a list of addresses, use the
format_addresses()function to first convert the addresses to a string.
- Return type:
- Raises:
ValueError – if neither
textnorhtmlis set
Addresses
Addresses in eletter can be specified in three ways:
As an
"address@domain.com"string giving just a bare e-mail addressAs an
eletter.Address("Display Name", "address@domain.com")instance pairing a person’s name with an e-mail addressAs an
eletter.Group("Group Name", iterable_of_addresses)instance specifying a group of addresses (strings orAddressinstances)
Note
eletter.Address and eletter.Group are actually just subclasses of
Address and Group from
email.headerregistry with slightly more convenient constructors. You can
also use the standard library types directly, if you want to.
MailItem Classes
- class eletter.MailItem[source]
Added in version 0.3.0.
Base class for all
elettermessage components- compose(*, to: Iterable[str | Address | Group], from_: str | Address | Group | Iterable[str | Address | Group] | None = None, subject: str | None = None, cc: Iterable[str | Address | Group] | None = None, bcc: Iterable[str | Address | Group] | None = None, reply_to: str | Address | Group | Iterable[str | Address | Group] | None = None, sender: str | Address | None = None, date: datetime | None = None, headers: Mapping[str, str | Iterable[str]] | None = None) EmailMessage[source]
Convert the
MailIteminto anEmailMessagewith the item’s contents as the payload and with the given subject, From address, To addresses, and optional other headers.All parameters other than
toare optional.Changed in version 0.4.0:
from_may now beNoneor omitted.Changed in version 0.4.0: All arguments are now keyword-only.
Changed in version 0.5.0:
subjectmay now beNoneor omitted.- Parameters:
subject (str) – The e-mail’s Subject line
to (iterable of addresses) – The e-mail’s To line
from_ (address or iterable of addresses) – The e-mail’s From line. Note that this argument is spelled with an underscore, as “
from” is a keyword in Python.cc (iterable of addresses) – The e-mail’s CC line
bcc (iterable of addresses) – The e-mail’s BCC line
reply_to (address or iterable of addresses) – The e-mail’s Reply-To line
sender (address) – The e-mail’s Sender line. The address must be a string or
Address, not aGroup.date (datetime) – The e-mail’s Date line
headers (mapping) – 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 Resent-From to a list of addresses, use the
format_addresses()function to first convert the addresses to a string.
- Return type:
Attachments
- class eletter.BytesAttachment(content: bytes, filename: str | None, *, content_id: str | None = None, content_type: str = NOTHING, inline: bool = False)[source]
A binary e-mail attachment.
content_typedefaults to"application/octet-stream".- filename: str | None
The filename of the attachment
Changed in version 0.5.0:
filenamecan now beNone.
- classmethod from_file(path: bytes | str | PathLike[bytes] | PathLike[str], content_type: str | None = None, inline: bool = False, content_id: str | None = None) BytesAttachment[source]
Added in version 0.2.0.
Construct a
BytesAttachmentfrom the contents of the file atpath. The filename of the attachment will be set to the basename ofpath. Ifcontent_typeisNone, the Content-Type is guessed based onpath’s file extension.Changed in version 0.3.0:
inlineandcontent_idarguments added
- class eletter.EmailAttachment(content: EmailMessage, filename: str | None, *, content_id: str | None = None, inline: bool = False)[source]
Added in version 0.2.0.
A message/rfc822 e-mail attachment
- content: EmailMessage
The body of the attachment
- filename: str | None
The filename of the attachment
Changed in version 0.5.0:
filenamecan now beNone.
- class eletter.TextAttachment(content: str, filename: str | None, *, content_id: str | None = None, content_type: str = NOTHING, inline: bool = False)[source]
A textual e-mail attachment.
content_typedefaults to"text/plain"and must have a maintype of text.- filename: str | None
The filename of the attachment
Changed in version 0.5.0:
filenamecan now beNone.
- classmethod from_file(path: bytes | str | PathLike[bytes] | PathLike[str], content_type: str | None = None, encoding: str | None = None, errors: str | None = None, inline: bool = False, content_id: str | None = None) TextAttachment[source]
Added in version 0.2.0.
Construct a
TextAttachmentfrom the contents of the file atpath. The filename of the attachment will be set to the basename ofpath. Ifcontent_typeisNone, the Content-Type is guessed based onpath’s file extension.encodinganderrorsare used when opening the file and have no relation to the Content-Type.Changed in version 0.3.0:
inlineandcontent_idarguments added
Body Classes
Multipart Classes
- class eletter.Multipart[source]
Added in version 0.3.0.
Base class for all multipart classes. All such classes are mutable sequences of
MailItems supporting the usual methods (construction from an iterable, subscription,append(),pop(), etc.).
- class eletter.Alternative(content: Iterable[MailItem] = NOTHING, *, content_id: str | None = None)[source]
Added in version 0.3.0.
A multipart/alternative e-mail payload. E-mails clients will display the resulting payload by choosing whichever part they support best.
An
Alternativeinstance can be created by combining two or moreMailItems with the|operator:text = TextBody("This is displayed on plain text clients.\n") html = HTMLBody("<p>This is displayed on graphical clients.<p>\n") alternative = text | html
Likewise, additional
MailItems can be added to anAlternativeinstance with the|=operator:# Same as above: alternative = Alternative() alternative |= TextBody("This is displayed on plain text clients.\n") alternative |= HTMLBody("<p>This is displayed on graphical clients.<p>\n")
Using
|to combine aMailItemwith astrautomatically converts thestrto aTextBody:# Same as above: text = "This is displayed on plain text clients.\n" html = HTMLBody("<p>This is displayed on graphical clients.<p>\n") alternative = text | html assert alternative.contents == [ TextBody("This is displayed on plain text clients.\n"), HTMLBody("<p>This is displayed on graphical clients.<p>\n"), ]
When combining two
Alternativeinstances with|or|=, the contents are “flattened”:# Same as above: txtalt = Alternative([ TextBody("This is displayed on plain text clients.\n") ]) htmlalt = Alternative([ HTMLBody("<p>This is displayed on graphical clients.<p>\n") ]) alternative = txtalt | htmlalt assert alternative.contents == [ TextBody("This is displayed on plain text clients.\n"), HTMLBody("<p>This is displayed on graphical clients.<p>\n"), ]
- class eletter.Mixed(content: Iterable[MailItem] = NOTHING, *, content_id: str | None = None)[source]
Added in version 0.3.0.
A multipart/mixed e-mail payload. E-mails clients will display the resulting payload one part after another, with attachments displayed inline if their
inlineattribute is set.A
Mixedinstance can be created by combining two or moreMailItems with the&operator:text = TextBody("Look at the pretty kitty!\n") image = BytesAttachment.from_file("snuffles.jpeg", inline=True) sig = TextBody("Sincerely, Me\n") mixed = text & image & sig
Likewise, additional
MailItems can be added to aMixedinstance with the&=operator:# Same as above: mixed = Mixed() mixed &= TextBody("Look at the pretty kitty!\n") mixed &= BytesAttachment.from_file("snuffles.jpeg", inline=True) mixed &= TextBody("Sincerely, Me\n")
Using
&to combine aMailItemwith astrautomatically converts thestrto aTextBody:# Same as above: image = BytesAttachment.from_file("snuffles.jpeg", inline=True) mixed = "Look at the pretty kitty!\n" & image & "Sincerely, Me\n" assert mixed.contents == [ TextBody("Look at the pretty kitty!\n"), BytesAttachment.from_file("snuffles.jpeg", inline=True), TextBody("Sincerely, Me\n"), ]
When combining two
Mixedinstances with&or&=, the contents are “flattened”:part1 = Mixed() part1 &= TextBody("Look at the pretty kitty!\n") part1 &= BytesAttachment.from_file("snuffles.jpeg", inline=True) part2 = Mixed() part2 &= TextBody("Now look at this dog.\n") part2 &= BytesAttachment.from_file("rags.jpeg", inline=True) part2 &= TextBody("Which one is cuter?\n") mixed = part1 & part2 assert mixed.contents == [ TextBody("Look at the pretty kitty!\n"), BytesAttachment.from_file("snuffles.jpeg", inline=True), TextBody("Now look at this dog.\n"), BytesAttachment.from_file("rags.jpeg", inline=True), TextBody("Which one is cuter?\n"), ]
- class eletter.Related(content: Iterable[MailItem] = NOTHING, start: str | None = None, *, content_id: str | None = None)[source]
Added in version 0.3.0.
A multipart/related e-mail payload. E-mail clients will display the part indicated by the
startparameter, or the first part ifstartis not set. This part may refer to other parts (e.g., images or CSS stylesheets) by their Content-ID headers, which can be generated usingemail.utils.make_msgid.Note
Content-ID headers begin & end with angle brackets (
<...>), which need to be stripped off before including the ID in the starting part.A
Relatedinstance can be created by combining two or moreMailItems with the^operator:from email.utils import make_msgid img_cid = make_msgid() html = HTMLBody( "<p>Look at the pretty kitty!</p>" f'<img src="cid:{img_cid[1:-1]}"/>" "<p>Isn't he <em>darling</em>?</p>" ) image = BytesAttachment.from_file("snuffles.jpeg", content_id=img_cid) related = html ^ image
Likewise, additional
MailItems can be added to aRelatedinstance with the^=operator:# Same as above: img_cid = make_msgid() related = Related() related ^= HTMLBody( "<p>Look at the pretty kitty!</p>" f'<img src="cid:{img_cid[1:-1]}"/>" "<p>Isn't he <em>darling</em>?</p>" ) related ^= BytesAttachment.from_file("snuffles.jpeg", content_id=img_cid)
Using
^to combine aMailItemwith astrautomatically converts thestrto aTextBody, though this is generally not all that useful, as you’ll usually want to createRelatedinstances fromHTMLBodys instead.When combining two
Relatedinstances with^or^=, the contents are “flattened”:# Same as above: img_cid = make_msgid() htmlrel = Related([ HTMLBody( "<p>Look at the pretty kitty!</p>" f'<img src="cid:{img_cid[1:-1]}"/>" "<p>Isn't he <em>darling</em>?</p>" ) ]) imgrel = Related([ BytesAttachment.from_file("snuffles.jpeg", content_id=img_cid) ]) related = htmlrel ^ imgrel assert related.contents == [ HTMLBody( "<p>Look at the pretty kitty!</p>" f'<img src="cid:{img_cid[1:-1]}"/>" "<p>Isn't he <em>darling</em>?</p>" ), BytesAttachment.from_file("snuffles.jpeg", content_id=img_cid), ]
Changed in version 0.4.0: Using
^to combine aMailItemwith astrnow automatically converts thestrto aTextBody
Decomposition
- eletter.decompose(msg: EmailMessage) Eletter[source]
Added in version 0.5.0.
Decompose an
EmailMessageinto anEletterinstance containing aMailItemand a collection of headers. Only structures that can be represented byeletterclasses are supported.All message parts that are not text/plain, text/html, multipart/*, or message/* are treated as attachments. Attachments without filenames or an explicit “attachment” Content-Disposition are treated as inline.
Any information specific to how the message is encoded is discarded (namely, “charset” parameters on text/* parts, Content-Transfer-Encoding headers, and MIME-Version headers).
Headers on message sub-parts that do not have representations on
MailItems are discarded (namely, everything other than Content-Type, Content-Disposition, and Content-ID).- Raises:
TypeError – if any sub-part of
msgis not anEmailMessageinstanceDecompositionError – if
msgcontains a part with an unrepresentable Content-Type
- eletter.decompose_simple(msg: EmailMessage, unmix: bool = False) SimpleEletter[source]
Added in version 0.5.0.
Decompose an
EmailMessageinto aSimpleEletterinstance consisting of a text body and/or HTML body, some number of attachments, and a collection of headers. TheEmailMessageis first decomposed withdecompose()and then simplified by callingEletter.simplify().By default, a multipart/mixed message can only be simplified if all of the attachments come after all of the message bodies; set
unmixtoTrueto separate the attachments from the bodies regardless of what order they come in.- Raises:
TypeError – if any sub-part of
msgis not anEmailMessageinstanceDecompositionError – if
msgcontains a part with an unrepresentable Content-TypeSimplificationError – if
msgcannot be simplified
- class eletter.Eletter[source]
Added in version 0.5.0.
A decomposed e-mail message
- headers: dict[str, list[str]]
Any additional headers on the message. The header names are lowercase.
- compose() EmailMessage[source]
Convert the
Eletterback into anEmailMessage
- simplify(unmix: bool = False) SimpleEletter[source]
Simplify the
Eletterinto aSimpleEletter, breaking downEletter.contentinto a text body, HTML body, and a list of attachments.By default, a multipart/mixed message can only be simplified if all of the attachments come after all of the message bodies; set
unmixtoTrueto separate the attachments from the bodies regardless of what order they come in.- Raises:
SimplificationError – if
msgcannot be simplified
- class eletter.SimpleEletter[source]
Added in version 0.5.0.
A decomposed simple e-mail message, consisting of a text body and/or HTML body plus some number of attachments and headers
- attachments: list[Attachment]
Attachments on the message
- headers: dict[str, list[str]]
Any additional headers on the message. The header names are lowercase.
- compose() EmailMessage[source]
Convert the
SimpleEletterback into anEmailMessage
Exceptions
- exception eletter.Error[source]
Bases:
ExceptionAdded in version 0.5.0.
The superclass of all custom exceptions raised by
eletter
- exception eletter.DecompositionError[source]
Bases:
Error,ValueErrorAdded in version 0.5.0.
Raised when
eletteris asked to decompose anEmailMessagewith an unrepresentable Content-Type
- exception eletter.SimplificationError[source]
Bases:
Error,ValueErrorAdded in version 0.5.0.
Raised when
eletteris asked to simplify a message that cannot be simplified
- exception eletter.MixedContentError[source]
Bases:
SimplificationErrorAdded in version 0.5.0.
Subclass of
SimplificationErrorraised when a multipart/mixed is encountered in which one or more attachments precede a message body part; such messages can be forced to be simplified by setting theunmixargument ofsimplify()ordecompose_simple()toTrue.
Utility Functions
- eletter.assemble_content_type(maintype: str, subtype: str, **params: str) str[source]
Added in version 0.2.0.
Construct a Content-Type string from a maintype, subtype, and some number of parameters
- Raises:
ValueError – if
f"{maintype}/{subtype}"is an invalid Content-Type
- eletter.format_addresses(addresses: Iterable[str | Address | Group], encode: bool = False) str[source]
Convert an iterable of e-mail address strings (of the form “
foo@example.com”, without angle brackets or a display name),Addressobjects, and/orGroupobjects into a formatted string. IfencodeisFalse(the default), non-ASCII characters are left as-is. If it isTrue, non-ASCII display names are converted into RFC 2047 encoded words, and non-ASCII domain names are encoded using Punycode.
- eletter.reply_quote(s: str, prefix: str = '> ') str[source]
Added in version 0.2.0.
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.