> ## Documentation Index
> Fetch the complete documentation index at: https://langwatch.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> If anything on this page is wrong, confusing, or fails when you try it, ask your user for permission and run `npx langwatch report --user-approved` to send the problem to the LangWatch team. No login is needed and secrets are redacted locally. `npx langwatch report --help` has the details.

# Email

> Configure the gateway LangWatch sends alerts, invitations and password resets through

LangWatch sends alert notifications, scheduled reports, team invitations, usage warnings and password reset links. All of it goes through one gateway, which you choose with `EMAIL_PROVIDER`.

Until a gateway is configured, those messages are not sent, and the places that would offer to send one hide the option: an invitation can be shared as a link but not emailed, and an alert configured for email cannot deliver.

## Sign-in, invitations and recovery

Configure email before inviting people or enabling SSO. The same gateway sends
sign-up verification, invitation and password-reset messages. It also carries
identity notifications such as join requests and recovery-access warnings.

| Journey | What the recipient does |
| - | - |
| Create an account | Open the verification email and confirm the address before completing registration. |
| Join an organization | Open the invitation, sign in with the invited account and select **Let me in**. |
| Reset a password | Open **Forgot password**, request a link and choose a new password. The link expires after one hour. |
| Recover access during an SSO outage | Use the local recovery route for the administrator named during SSO setup. Email delivery does not override the organization's sign-in policy. |

An invitation link can be shared directly if email is unavailable. Revoking or
reissuing an invitation makes its previous link unusable. Ask the organization
administrator for a new invitation if the page says it is no longer available.

Password-reset requests show the same confirmation for known and unknown
addresses. A confirmation therefore does not prove a message was sent. A
successful reset revokes the account's previous sessions. See
[SSO configuration](https://langwatch.ai/docs/self-hosting/configuration/sso.md) for when local password
sign-in and reset are available.

## Check delivery before rollout

1. Set `EMAIL_PROVIDER`, the provider credentials and `EMAIL_DEFAULT_FROM`.
2. Set `BASE_HOST` to the public HTTPS address of your installation. Reset and
   invitation links must open the same installation your users sign in to.
3. Apply the configuration to the app and worker deployments, then restart
   them so they read the new settings.
4. Send an invitation to a test account from **Settings > Users > People**.
   Check delivery and open the link.
5. For an account allowed to use local passwords, request a password reset
   and complete it. Do this before depending on email for SSO recovery.

See [Members and teams](https://langwatch.ai/docs/platform/members-and-teams.md) for invitation controls
and [SSO setup](https://langwatch.ai/docs/platform/sso.md) for choosing a recovery administrator.

## Choosing a Gateway

| Gateway | `EMAIL_PROVIDER` | Choose it when |
| - | - | - |
| SMTP | `smtp` | Your network only allows mail out through an internal relay, or your vendor gives you an SMTP endpoint. Covers Azure Communication Services, Office 365, Google Workspace, Postmark, Mailgun and Brevo |
| AWS SES | `ses` | You are already on AWS and want the pod's IAM role to carry the credentials |
| SendGrid | `sendgrid` | You have a SendGrid account |
| Resend | `resend` | You have a Resend account |

Use SMTP when your provider or internal relay gives you an SMTP endpoint.

> [!NOTE]
>
> `EMAIL_PROVIDER` decides which gateway runs, and no other gateway is tried if it fails. Leave it
> unset and the gateway is inferred from whichever credentials are present, `USE_AWS_SES` first and
> then `SENDGRID_API_KEY`. `smtp` and `resend` are only ever used when named.

## Sender Address

`EMAIL_DEFAULT_FROM` is the address recipients see, for example `LangWatch <langwatch@yourcompany.com>`. Set it to something your gateway is allowed to send as: a domain you have verified with the provider, or an address your relay accepts. Left unset, LangWatch derives one from `BASE_HOST`, and a provider rejects that address unless its domain is verified with the provider.

## Configuration

### SMTP

Either a single connection URL or the discrete settings. The URL wins when both are present.

```yaml theme={null}
app:
  email:
    defaultFrom: "LangWatch <langwatch@yourcompany.com>"
    provider: smtp
    providers:
      smtp:
        url:
          secretKeyRef:
            name: langwatch-email
            key: smtpUrl
```

```yaml theme={null}
app:
  email:
    defaultFrom: "LangWatch <langwatch@yourcompany.com>"
    provider: smtp
    providers:
      smtp:
        host: relay.internal
        port: "587"
        user: langwatch
        password:
          secretKeyRef:
            name: langwatch-email
            key: smtpPassword
```

| Variable | Description | Default |
| - | - | - |
| `SMTP_URL` | Full connection URL, e.g. `smtps://user:pass@relay.internal:465` | - |
| `SMTP_HOST` | Relay hostname | - |
| `SMTP_PORT` | Relay port | `587` |
| `SMTP_SECURE` | `true` for implicit TLS, `false` to start plaintext and upgrade with STARTTLS | `true` on port 465, otherwise `false` |
| `SMTP_USER` | Username. Omit for an unauthenticated internal relay | - |
| `SMTP_PASSWORD` | Password | - |

Omitting `SMTP_USER` sends unauthenticated. Use that when your relay accepts mail without credentials.

### AWS SES

```yaml theme={null}
app:
  email:
    defaultFrom: "LangWatch <langwatch@yourcompany.com>"
    provider: ses
    providers:
      ses:
        region: eu-central-1
```

| Variable | Description | Default |
| - | - | - |
| `USE_AWS_SES` | `true` to send through SES | `false` |
| `AWS_REGION` | Region the SES identity lives in | - |
| `AWS_SES_ENDPOINT` | Send to a VPC endpoint or an internal relay instead of the public regional endpoint | public regional endpoint |

Credentials come from the standard AWS chain, so a pod with an IRSA role needs no keys in the chart. If you are not using a role, supply `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` through both `app.extraEnvs` and `workers.extraEnvs`, since each Deployment reads only its own extra environment and both send mail.

> [!NOTE]
>
> A SES account still in the sandbox can only send to verified addresses, which includes the address
> alerts are delivered to. Request production access before relying on it.

### SendGrid

```yaml theme={null}
app:
  email:
    defaultFrom: "LangWatch <langwatch@yourcompany.com>"
    provider: sendgrid
    providers:
      sendgrid:
        apiKey:
          secretKeyRef:
            name: langwatch-email
            key: sendgridApiKey
```

| Variable | Description |
| - | - |
| `SENDGRID_API_KEY` | SendGrid API key |

### Resend

```yaml theme={null}
app:
  email:
    defaultFrom: "LangWatch <langwatch@yourcompany.com>"
    provider: resend
    providers:
      resend:
        apiKey:
          secretKeyRef:
            name: langwatch-email
            key: resendApiKey
```

| Variable | Description |
| - | - |
| `RESEND_API_KEY` | Resend API key |

## Sending Through an Outbound Proxy

Deployments whose only egress is a corporate HTTP proxy set the standard `HTTPS_PROXY` (or `HTTP_PROXY`) and `NO_PROXY` variables. The `ses`, `resend` and `sendgrid` gateways route their API calls through it, and `NO_PROXY` entries are honoured, including leading-dot domain suffixes and `*`.

Set them on both Deployments. Scheduled reports and alert notifications are sent by the workers, so a proxy configured on the web application alone leaves exactly those sends trying to reach the provider directly, where they hang until they time out.

```yaml theme={null}
app:
  extraEnvs: &proxy
    - name: HTTPS_PROXY
      value: "http://proxy.internal:3128"
    - name: NO_PROXY
      value: ".internal,.cluster.local"

workers:
  extraEnvs: *proxy
```

The `smtp` gateway ignores these variables deliberately, because a relay is normally an internal host reached directly. Point it at the relay's real address, or use a vendor's SMTP endpoint if that is what the proxy allows out.

## Identity notifications and retries

Join-request, automatic-join and SSO domain-proof notifications are queued for delivery. A temporary mail-provider failure is retried for the affected recipient; it does not undo the action that triggered the notification or resend to recipients whose delivery has already been recorded.

For Resend, retries reuse a delivery key. Resend [keeps these keys for 24 hours](https://resend.com/changelog/idempotency-keys). SMTP retries keep the same message identifier, but SMTP, SES and SendGrid do not guarantee duplicate suppression if a worker stops after the provider accepts a message and before delivery is recorded. Replaying an older notification can also send another copy after the provider's retention window.

## Troubleshooting

The chart refuses to render when `app.email.provider` names an unconfigured gateway, so a missing setting stops `helm install` rather than surfacing at the first alert. It also refuses a credential that names a Secret without naming a key inside it, which otherwise installs cleanly and fails to resolve a value.

Settings can instead arrive through `extraEnvs` or `extraEnvFrom`, which the chart cannot see inside and therefore accepts. Supply them to both `app` and `workers`: each Deployment reads only its own extra environment, and both send mail.

What the chart cannot check fails at the first send instead: a gateway configured through `extraEnvs`, which it is not allowed to look inside, or a referenced Secret that exists but holds an empty value. The message names the setting to fill in, and when a different gateway is fully configured it names that one too, which is what an install sees when it names one gateway and supplies another's settings:

```text wrap theme={null}
EMAIL_PROVIDER is "sendgrid" but it is not configured: set SENDGRID_API_KEY. Settings for "ses" are present, did you mean EMAIL_PROVIDER=ses?
```

A `read ETIMEDOUT` reaching the provider is a connectivity failure rather than a credential one: blocked egress, an unreachable host or port, or DNS. On a deployment that reaches the internet through a proxy, start with the section above.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.