---
title: Mail
description: Send email from hooks, agents, jobs and server functions, through one mail server set up in the admin UI.
section: Server
order: 5
---

# Mail

<p class="lead">Configure SMTP once, then send from any server code with <code>mail()</code>. Sign-in links, invitations, password resets and notifications all go through it.</p>

## Setting it up

In the admin UI, under **Mail**:

| | |
|---|---|
| Host and port | Your provider's SMTP server: `smtp.example.com`, `587` |
| Username, password | The password stays on the server and is never returned by the API |
| From, from name | Sender address and display name, e.g. "Springfield Elementary" |
| Base URL | Where links in emails point. Defaults to the address the app is served at |
| TLS | STARTTLS; turn it off only for a local relay that doesn't support it |

Without a host, mail is disabled: nothing fails, nothing is sent.

## Sending

```ts title="agents/receipts.ts"
export async function act({ event, mail, link }) {
  const sent = await mail({
    to: event.data.email,
    subject: "Paid, thank you",
    text: `Your order is paid. See it at ${await link("/orders")}`,
  });
}
```

- `mail({ to, subject, text })` resolves to `true` if sent, `false` if mail isn't configured or the server rejected it. Failures are logged, never thrown.
- `link(path)` turns an app path into an absolute URL using the base URL.

Mail is plain text on purpose. A notification points to something in the app and links to it; it isn't the conversation itself, so nobody replies to an unread inbox.

## Built-in emails

Sign-in links, password resets and invitations, in the app's language. [Conversation](/docs/client#and-the-rest) threads email participants who were offline when a message arrived; chat rooms never email, to keep inboxes quiet.
