# Send emails with Gitea

> Point Gitea's mailer at PostShiba.

## What you'll build

A self-hosted Gitea 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 Gitea's `app.ini`, or to the container environment for a Docker install. The keys here are for Gitea 1.18 and later.

## Install

Nothing to install. Gitea 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 [Gitea's config cheat sheet](https://docs.gitea.com/administration/config-cheat-sheet#mailer-mailer).

```ini app.ini
[mailer]
ENABLED = true
FROM = "Gitea <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 Gitea checks the server certificate. Leave `ENVELOPE_FROM` unset, so the envelope sender is the `FROM` address. Gitea has no auth-method setting. It picks one from what the server offers and uses `AUTH PLAIN` with PostShiba.

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 Gitea so it reloads the config. On a systemd install:

```sh restart.sh
sudo systemctl restart gitea
```

4. In Gitea, go to **Site Administration** → **Configuration** → **Summary**. Under **Mailer Configuration**, enter your address in **Send Testing 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 official Gitea image reads `GITEA__<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:
      - GITEA__mailer__ENABLED=true
      - GITEA__mailer__FROM=hello@mail.example.com
      - GITEA__mailer__PROTOCOL=smtp+starttls
      - GITEA__mailer__SMTP_ADDR=smtp.postshiba.com
      - GITEA__mailer__SMTP_PORT=587
      - GITEA__mailer__USER=smtp_9
      - GITEA__mailer__PASSWD=YOUR_PASSWORD
```

To keep the password out of the compose file, append `__FILE` to the name and point it at a file, such as a Docker secret: `GITEA__mailer__PASSWD__FILE=/run/secrets/smtp_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 Gitea log shows | What to do |
| --- | --- |
| `SMTP server does not support AUTH, but credentials provided` | Gitea 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 Gitea. |

## 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.
