# Send emails with Forgejo

> Point Forgejo's mailer at PostShiba.

## What you'll build

A self-hosted Forgejo instance that sends its notification mail, such as registration confirmations, password resets, and issue and pull request notifications, through PostShiba over SMTP. Use a Transactional cluster for this mail.

## Before you start

- An SMTP username and password. Open your cluster in the dashboard, go to its SMTP credentials, and choose **Create SMTP credential**. Copy the password right away, because it is shown once. You can also use the [SMTP credentials API](/docs/api-reference/smtp-credentials).
- A verified sending domain. See [Add and verify a domain](/docs/add-a-domain). The `FROM` address must be on it.
- A cluster that is ready to send (`sending_ready` is `true`). See [Clusters](/docs/dashboard/clusters/introduction).
- Access to Forgejo's `app.ini`, or to the container environment for a Docker install.

## Install

Nothing to install. Forgejo has SMTP support built in.

## Send your first email

1. Set the `[mailer]` section in `app.ini`. `PROTOCOL = smtp+starttls` on port 587 upgrades the connection with STARTTLS. Wrap the password in backticks if it has special characters. The keys follow [Forgejo's config cheat sheet](https://forgejo.org/docs/latest/admin/config-cheat-sheet/#mailer-mailer).

```ini app.ini
[mailer]
ENABLED = true
FROM = "Forgejo <hello@mail.example.com>"
PROTOCOL = smtp+starttls
SMTP_ADDR = smtp.postshiba.com
SMTP_PORT = 587
USER = smtp_9
PASSWD = `YOUR_PASSWORD`
FORCE_TRUST_SERVER_CERT = false
```

Keep `FORCE_TRUST_SERVER_CERT` at `false` so Forgejo checks the server certificate. Leave `ENVELOPE_FROM` unset, so the envelope sender is the `FROM` address. Forgejo has no auth-method setting. It picks one from what the server offers and uses `AUTH PLAIN` with PostShiba.

To keep the password out of `app.ini`, replace `PASSWD` with `PASSWD_URI` pointing at a file, such as `PASSWD_URI = file:/etc/forgejo/mailer_passwd`. Set one or the other, not both.

2. To mail issue and pull request notifications, set `ENABLE_NOTIFY_MAIL = true` in the `[service]` section. To make new users confirm their address, set `REGISTER_EMAIL_CONFIRM = true` there too.

3. Restart Forgejo so it reloads the config. On a systemd install:

```sh restart.sh
sudo systemctl restart forgejo
```

4. In Forgejo, go to **Site administration** → **Configuration** → **Summary**. Under **Mailer configuration**, enter your address in **Send test email** and choose **Send**. The message goes through PostShiba and shows under Events in the dashboard.

Every SMTP setting is on [Send emails with SMTP](/docs/send-with-smtp).

## Docker

The Forgejo container image reads `FORGEJO__<section>__<KEY>` environment variables into `app.ini` on container startup. Set the same keys in `docker-compose.yml`, then run `docker compose up -d` to recreate the container.

```yaml docker-compose.yml
services:
  server:
    environment:
      - FORGEJO__mailer__ENABLED=true
      - FORGEJO__mailer__FROM=hello@mail.example.com
      - FORGEJO__mailer__PROTOCOL=smtp+starttls
      - FORGEJO__mailer__SMTP_ADDR=smtp.postshiba.com
      - FORGEJO__mailer__SMTP_PORT=587
      - FORGEJO__mailer__USER=smtp_9
      - FORGEJO__mailer__PASSWD=YOUR_PASSWORD
```

## Troubleshooting

When the cluster reaches its hourly throttle or 24-hour cap, SMTP answers `451 4.7.0 hourly send limit reached` or `451 4.7.0 daily send limit reached` and does not keep the message. Retry once the cap has room. See [What happens at your cap](/docs/dashboard/clusters/what-happens-at-your-cap).

| What the test email or Forgejo log shows | What to do |
| --- | --- |
| `SMTP server does not support AUTH, but credentials provided` | Forgejo did not start TLS. Set `PROTOCOL = smtp+starttls` and `SMTP_PORT = 587`. |
| `failed to authenticate SMTP` | Check `USER` and `PASSWD`. Wrap the password in backticks if it has special characters. |
| `454 4.7.0 too many failed logins, try again later` | Too many wrong passwords. Fix `PASSWD`, then try again. |
| `failed to start TLS connection` with a certificate error | Check that `SMTP_ADDR` is `smtp.postshiba.com`. Keep `FORCE_TRUST_SERVER_CERT = false`. |
| `550 unverified domain` or `550 from header not aligned with verified domain` | Set `FROM` to an address on your verified domain, and leave `ENVELOPE_FROM` unset. |
| `550 domain_suspended` | The From domain is paused. Resume it from [Managing domains](/docs/dashboard/domains/manage-domains). |
| `550 kyc_required` | Your team is pending production approval. Until then, send only to team members, live inbox addresses, and inbox forward-to addresses. See [Production approval](/docs/knowledge-base/does-capsule-require-production-approval). |
| `550 suppressed` or `550 firewall: <rule>` | The recipient is on the [suppression list](/docs/dashboard/emails/email-suppressions) or failed an [email firewall](/docs/dashboard/emails/email-firewall) check. |
| Test email arrives, but no issue or pull request notifications | Set `ENABLE_NOTIFY_MAIL = true` in `[service]` and restart Forgejo. |

## Next steps

- [Send emails with SMTP](/docs/send-with-smtp) for every setting and reply.
- [AUTH PLAIN, not AUTH LOGIN](/docs/knowledge-base/auth-plain)
- [Managing webhooks](/docs/webhooks/introduction) to receive delivery events.
