## Message


A message holds the content, addressing, subject, custom headers, and attachments a caller builds, as one frozen value.


Usage

``` python
Message(
    *,
    html=None,
    markdown=None,
    text=None,
    text_renderer=None,
)
```


It compares and hashes by content. Every builder method returns a new message and leaves the receiver unchanged.

A method named for a field replaces that field, so `.to("a").to("b")` addresses `b` alone. `.attach()` and `.embed()` append instead. Nothing removes a field, so each address method takes at least one address. See ADR-0002.

A builder method's value is an attribute with the method's name plus a trailing underscore, because the plain name is the method. See ADR-0007.


## Parameters


`html: str | None = None`  
The HTML. Epistole moves each `data:` image in an `<img src>` into an inline image and rewrites the `src` to `cid:`. It then derives the plain text from the result with [html_to_text](html_to_text.md#epistole.html_to_text), unless the caller supplies `text` or `text_renderer`. See ADR-0003.

`markdown: str | None = None`  
The Markdown source. Epistole renders the HTML from it on markdown-it-py's `commonmark` preset and sends the source as the plain text, unless the caller supplies `text`.

`text: str | None = None`  
The plain text. Epistole sends it verbatim and derives nothing from `html`. It may be `""` when the subject holds the whole message.

`text_renderer: Callable[[str], str] | None = None`  
Derives the plain text from the rewritten `html` in place of [html_to_text](html_to_text.md#epistole.html_to_text). It runs once, at construction. The message does not keep it, so equality compares content alone. An exception it raises propagates unchanged.


## Attributes


`to_, cc_, bcc_, reply_to_`  
The addresses the builder method of the same name set.

`subject_: str | None`  
The subject `.subject()` set, or `None`.

`headers_: Mapping[str, str]`  
The custom headers `.headers()` set, as a read-only mapping in the caller's order. It is empty until `.headers()` sets it, and it never holds a header Epistole writes.

`html: str | None`  
The HTML the caller supplied or Epistole rendered from `markdown`, or `None` on a text-only message. The rewrite has replaced each `data:` image in it with a `cid:` reference.

`text: str`  
The plain text. It is the Markdown source for `markdown=`. It is `""` for `text=""`, and also for HTML that holds no text, such as a lone image with no alt text.

`attachments: tuple[Attachment, …]`  
What `.attach()` added, in call order.

`inline_images: tuple[Attachment, …]`  
The inline images the `data:` rewrite made come first, one per distinct media type and bytes. What `.embed()` added follows, in call order.


## Raises


`TypeError`  
When both `html` and `markdown` are supplied, when no content is supplied, or when `text_renderer` accompanies `text` or `markdown`. When `html`, `markdown`, or `text` is not a `str`, or when `text_renderer` returns something other than a `str`.

`ValueError`  
When `html`, `markdown`, or `text` holds a surrogate, or when `text_renderer` returns text that holds one. When the payload of a `data:` image does not decode. See ADR-0003 and ADR-0008.

`ImportError`  
When `markdown` is supplied and `epistole[markdown]` is not installed.


## Methods

| Name | Description |
|----|----|
| [to()](#to) | Return a copy with the to addresses set, replacing any earlier `.to()`. |
| [cc()](#cc) | Return a copy with the cc addresses set, replacing any earlier `.cc()`. |
| [bcc()](#bcc) | Return a copy with the bcc addresses set, replacing any earlier `.bcc()`. |
| [reply_to()](#reply_to) | Return a copy with the reply-to addresses set, replacing any earlier `.reply_to()`. |
| [subject()](#subject) | Return a copy with the subject set, replacing any earlier subject. |
| [headers()](#headers) | Return a copy with the custom headers set, replacing any earlier `.headers()`. |
| [attach()](#attach) | Return a copy with `source` appended as an attachment. |
| [embed()](#embed) | Return a copy with `source` appended as an inline image, which the HTML names as `cid:` plus its content id. |

------------------------------------------------------------------------


#### to()


Return a copy with the to addresses set, replacing any earlier `.to()`.


Usage

``` python
to(address, /, *more)
```


------------------------------------------------------------------------


#### cc()


Return a copy with the cc addresses set, replacing any earlier `.cc()`.


Usage

``` python
cc(address, /, *more)
```


------------------------------------------------------------------------


#### bcc()


Return a copy with the bcc addresses set, replacing any earlier `.bcc()`.


Usage

``` python
bcc(address, /, *more)
```


------------------------------------------------------------------------


#### reply_to()


Return a copy with the reply-to addresses set, replacing any earlier `.reply_to()`.


Usage

``` python
reply_to(address, /, *more)
```


------------------------------------------------------------------------


#### subject()


Return a copy with the subject set, replacing any earlier subject.


Usage

``` python
subject(subject)
```


##### Raises


`TypeError`  
When [subject](Message.md#epistole.Message.subject) is not a `str`.

`ValueError`  
When [subject](Message.md#epistole.Message.subject) holds a line break or a surrogate. See ADR-0016.


------------------------------------------------------------------------


#### headers()


Return a copy with the custom headers set, replacing any earlier `.headers()`.


Usage

``` python
headers(mapping)
```


It copies `mapping` at the call and keeps its order. See ADR-0016.


##### Raises


`TypeError`  
When a name or a value is not a `str`.

`ValueError`  
When `mapping` is empty, or when two names differ only in case. When a name holds a space, a colon, or a character outside printable ASCII. When a name is `Resent-Bcc` or a name Epistole writes. When a value holds a line break or a surrogate.


------------------------------------------------------------------------


#### attach()


Return a copy with `source` appended as an attachment.


Usage

``` python
attach(source, /, *, filename=None, content_type=None)
```


##### Parameters


`source: Path | bytes | BinaryIO`  
The bytes, or a `Path` or binary file object to read them from. Epistole reads it at call time. A `Path` supplies its own filename. A file object is read from its current position and left open.

`filename: str | None = None`  
The name the recipient sees. Bytes and a file object need one, because Epistole never reads a file object's `.name`.

`content_type: str | None = None`  
A bare media type such as `application/pdf`. It defaults to the type `filename` implies. It falls back to `application/octet-stream` when the filename implies no type, a compressed file, or a `message/*` or `multipart/*` type. Epistole never inspects the bytes.


##### Raises


`TypeError`  
When `source` is a `str`, a `bytearray`, a `memoryview`, or a text-mode file, or when the caller passes a source other than a `Path` without `filename`. When `filename` or `content_type` is not a `str`. See ADR-0018.

`ValueError`  
When the filename holds a line break or a surrogate, or when `content_type` is not a bare `type/subtype`, such as one with parameters or a name over 127 characters. When `content_type` is a `message/*` or `multipart/*` type. See ADR-0018.


------------------------------------------------------------------------


#### embed()


Return a copy with `source` appended as an inline image, which the HTML names as `cid:` plus its content id.


Usage

``` python
embed(source, /, *, filename=None, cid=None, content_type=None)
```


##### Parameters


`source: Path | bytes | BinaryIO`  
The image, read now, as for `.attach()`.

`filename: str | None = None`  
The name the recipient sees. It defaults to a `Path` source's own name, or else to `cid`.

`cid: str | None = None`  
The content id. It defaults to `filename`, so `.embed(Path("logo.png"))` matches `<img src="cid:logo.png">`.

`content_type: str | None = None`  
As for `.attach()`, and it must be `image/*`.


##### Raises


`TypeError`  
As for `.attach()`, or when the caller passes a source other than a `Path` with neither `filename` nor `cid`. When `cid` is not a `str`.

`ValueError`  
When the filename or the content id holds a line break, when the content id is not ASCII, when the content type is not `image/*`, or when the message already holds an inline image under the same content id, including one the `data:` rewrite made. When the filename or the content id holds a surrogate. See ADR-0018.
