@portable/mail
Functions
Mail.envelope
Returns the SMTP envelope for a message, the addresses a transport passes to MAIL FROM and
RCPT TO. Bcc recipients are included, although encodeStream leaves the Bcc header out.
Addresses are normalized as in the message headers, and each recipient is listed once. The
result can be spread into Smtp.send.
function envelope(message: {
readonly from?: Addresses | undefined;
readonly sender?: Addresses | undefined;
readonly to?: Addresses | undefined;
readonly cc?: Addresses | undefined;
readonly bcc?: Addresses | undefined;
}): Envelope;Throws
InvalidInputErrorWhen an address isn't one addr-spec, or the message has neither aFromnor aSenderaddress.
import * as Mail from '@portable/mail';
Mail.envelope({
from: 'Mari <mari@example.com>',
to: 'a@example.com, B <b@example.com>',
bcc: ['a@example.com', 'c@example.com'],
});
// { from: 'mari@example.com', to: ['a@example.com', 'b@example.com', 'c@example.com'] }Mail.encodeStream
Encodes a message as a raw RFC 5322 message, ready for an SMTP DATA command, an .eml file or
an API that takes raw MIME. Text and HTML become multipart/alternative, attachments with a
cid go into multipart/related beside the HTML, and other attachments into
multipart/mixed. Blob and stream content is read as the result is read.
encodeStream throws on mistakes in the message before it reads any content. A content stream that
fails errors the result, and cancelling the result cancels every content stream not yet read to
the end.
function encodeStream(
message: Message,
options: encodeStream.Options = {},
): ReadableStream<Uint8Array>;| Option | Type | Default | Description |
|---|---|---|---|
boundary | string | '=_' and 16 random hex digits and '_', which no base64 or quoted-printable line can contain | The prefix of every multipart boundary, up to 60 characters from RFC 2046's bchars. Each boundary is this prefix followed by the position of its multipart among all parts, counted from 1 in the order the parts are written. |
charset | any | UTF-8 | Charset for encoded words in headers and for text bodies given as strings, for mail that has to use one other than UTF-8. @portable/charset provides encoders. |
keepBcc | boolean | false | Write the Bcc header, for a transport such as sendmail that reads recipients from it. |
signal | AbortSignal | Errors the result with signal.reason and cancels every content stream not yet read. |
Throws
InvalidInputErrorWhen an address, header, content type, file name or date can't be written.TypeErrorWhen content isn't a string,Uint8Array,BloborReadableStream, or a stream is locked or given twice.
import * as Mail from '@portable/mail';
const raw = Mail.encodeStream({
from: 'Mari <mari@example.com>',
to: 'jaan@example.com',
subject: 'Tere',
text: 'Tere, Jaan!',
html: '<p>Tere, Jaan! <img src="cid:logo"></p>',
attachments: [
{ cid: 'logo', content: logoBytes, contentType: 'image/png' },
{
content: await (await fetch(reportUrl)).blob(),
filename: 'report.pdf',
},
],
});
await new Response(raw).text();Errors
Mail.InvalidInputError
Thrown by encodeStream and envelope when the message contains something that a mail header can't
hold as given: an address that isn't one addr-spec, a header name outside printable ASCII, a
header the package writes itself, a content type that isn't type/subtype or is multipart/*,
or an invalid Date. envelope also throws it for a message without a From or Sender
address.
class InvalidInputError extends Errors.InvalidInputError {
readonly kind: string;
}import * as Mail from '@portable/mail';
try {
Mail.encodeStream({ to: 'not an address', text: 'Hello' });
} catch (error) {
if (error instanceof Mail.InvalidInputError) {
console.log(error.message);
}
}Types
Mail.Addresses
The recipients or senders of one header: an address list as text, a Mailbox, or a list of
either.
type Addresses = string | Mailbox | readonly (string | Mailbox)[];Mail.Envelope
The SMTP envelope of a message: the MAIL FROM address and every RCPT TO address.
type Envelope = {
from: string;
to: readonly string[];
};Mail.Mailbox
One mailbox. Without a name, only the address is written.
type Mailbox = {
readonly name?: string | undefined;
readonly address: string;
};Mail.Content
A body or attachment: text (written as UTF-8), bytes, a Blob or File, or a stream of bytes
such as response.body. Blobs and streams are read only while the message is read, so a
large attachment is never held in memory.
type Content = string | Uint8Array | Blob | ReadableStream<Uint8Array>;Mail.TransferEncoding
How a part's bytes are written. 7bit and 8bit write them as they are, with line breaks
turned into CRLF.
type TransferEncoding = | | | ;Mail.Attachment
A file attached to the message, or an inline image the HTML refers to as cid:<cid>.
type Attachment = {
readonly content: Content;
readonly filename?: string | undefined;
readonly contentType?: string | undefined;
readonly cid?: string | undefined;
readonly disposition?: | | undefined;
readonly headers?: HeaderFields | undefined;
readonly transferEncoding?: TransferEncoding | undefined;
};Mail.HeaderFields
Extra header fields, by name. A list writes one field per value, in order.
type HeaderFields = Readonly<
Record<string, string | readonly string[]>
>;Mail.Message
A message to encode. Every field is optional, and a message with no body gets an empty text body.
type Message = {
readonly from?: Addresses | undefined;
readonly sender?: Addresses | undefined;
readonly to?: Addresses | undefined;
readonly cc?: Addresses | undefined;
readonly bcc?: Addresses | undefined;
readonly replyTo?: Addresses | undefined;
readonly inReplyTo?: string | undefined;
readonly references?: string | readonly string[] | undefined;
readonly subject?: string | undefined;
readonly messageId?: string | undefined;
readonly date?: Instant | string | undefined;
readonly text?: Content | undefined;
readonly amp?: Content | undefined;
readonly html?: Content | undefined;
readonly alternatives?: readonly Part[] | undefined;
readonly attachments?: readonly Attachment[] | undefined;
readonly headers?: HeaderFields | undefined;
};Mail.Part
An alternative body, such as a calendar invitation next to the text and HTML.
type Part = {
readonly content: Content;
readonly contentType: string;
readonly headers?: HeaderFields | undefined;
readonly transferEncoding?: TransferEncoding | undefined;
};