# gizlang:mail

the one way a program sends mail. A mailer is one URL that names the transport, its credentials and the sender, so a person sets it once (an environment variable, a settings field) and the program never branches on the provider:

smtp://USER:PASSWORD@HOST[:587]?from=SENDER     SMTP, upgraded with STARTTLS (plain only to this machine) smtps://USER:PASSWORD@HOST[:465]?from=SENDER    SMTP over TLS from the first byte ses://ACCESS:SECRET@REGION?from=SENDER[&configuration=SET]   Amazon SES (API v2, SigV4) resend://KEY@resend?from=SENDER                 Resend's API

The user name, password and key are percent-encoded in the URL. A message is plain text, with an HTML part when it has one; a sign-in or share link is never rewritten for click tracking. An error says what failed, never the body, the recipient, a credential or the provider's answer.

```gizlang
import * as Mail from "gizlang:mail";
```

## Types

### `Mailer`

```gizlang
type Mailer = { scheme: string; host: string; port: i64; user: string; secret: string; from: string; configuration: string; }
```

A transport: its scheme ("smtp", "smtps", "ses" or "resend"), host (an SES region), port, user (an access key),
secret (a password, an SES secret key, an API key), the sender (`from`: an address, or "Name <address>") and the
SES configuration set ("": none).

- `scheme`: `string`
- `host`: `string`
- `port`: `i64`
- `user`: `string`
- `secret`: `string`
- `from`: `string`
- `configuration`: `string`

### `Message`

```gizlang
type Message = { to: string; subject: string; text: string; html: string; key: string; }
```

One message: the recipient, the subject, the text, an HTML part ("": none) and a key that makes a retry the same
message where the transport supports it ("": none).

- `to`: `string`
- `subject`: `string`
- `text`: `string`
- `html`: `string`
- `key`: `string`

### `Transport`

```gizlang
type Transport = (host: string, request: Request) => Result<Response, string>
```

An HTTP exchange with `host` over TLS: the network, or a test's stand-in.

## Functions

### `message`

```gizlang
function message(to: string, subject: string, text: string): Message
```

A plain text message.

### `mailer`

```gizlang
function mailer(url: string): Result<Mailer, string>
```

The mailer of URL `url`, or why it is not one.

Effects: fail.

### `address`

```gizlang
function address(to: string): bool
```

Whether `to` is one email address that cannot carry another header.

Effects: fail.

### `send`

```gizlang
function send(sys: System, mailer: Mailer, m: Message): Result<string, string>
```

Sends `m` with `mailer` over the network: the provider's message id ("" when SMTP gives none), or why not.

Effects: fail, read, write, console, io.

### `sendWith`

```gizlang
function sendWith(mailer: Mailer, now: i64, m: Message, transport: Transport): Result<string, string>
```

Sends `m` with an HTTP mailer (ses, resend) at time `now` (ms) through `transport`.

Effects: fail, read, write, console, io.

## Constants

### `NOT_CONFIGURED`

```gizlang
const NOT_CONFIGURED = "Email is not configured."
```

What a program says when no mailer is set.

