https://github.com/solarssk/mail-autodiscover
Lightweight Outlook Autodiscover, Thunderbird Autoconfig and Apple Mail profile service for self-hosted mail servers.
https://github.com/solarssk/mail-autodiscover
apple-mail autoconfig autodiscover docker fastapi imap mail mailplus outlook self-hosted smtp synology thunderbird
Last synced: about 7 hours ago
JSON representation
Lightweight Outlook Autodiscover, Thunderbird Autoconfig and Apple Mail profile service for self-hosted mail servers.
- Host: GitHub
- URL: https://github.com/solarssk/mail-autodiscover
- Owner: solarssk
- License: mit
- Created: 2026-06-10T12:50:01.000Z (21 days ago)
- Default Branch: main
- Last Pushed: 2026-06-20T12:19:20.000Z (11 days ago)
- Last Synced: 2026-06-20T13:25:35.908Z (11 days ago)
- Topics: apple-mail, autoconfig, autodiscover, docker, fastapi, imap, mail, mailplus, outlook, self-hosted, smtp, synology, thunderbird
- Language: Python
- Homepage: https://github.com/solarssk/mail-autodiscover
- Size: 232 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
# mail-autodiscover
`mail-autodiscover` is a small deploy-and-forget HTTP service for self-hosted mail admins.
It exposes standard autodiscovery endpoints for:
- Outlook Autodiscover
- Thunderbird Autoconfig
- Apple Mail `.mobileconfig`
- POP3 in Thunderbird config when enabled for a domain
The product goal is deliberately narrow:
- stateless container
- no admin panel
- no database
- no mailbox existence checks
- no LDAP / Synology / directory lookups
If you want a small service you can deploy behind HTTPS and mostly forget about, this is what it is for.
## What It Does
For any syntactically valid mailbox in an allowed domain, the service returns the configured IMAP/SMTP settings and, optionally, POP3 for Thunderbird.
It does **not**:
- verify whether a mailbox exists
- expose your internal domain list on the landing page
- return different answers for existing vs non-existing mailboxes
- manage users or credentials
## Quick Start
1. Copy [`.env.example`](.env.example) to `.env`.
2. Choose one configuration mode:
- single/global config in ENV
- multi-domain config in [`config/config.example.yaml`](config/config.example.yaml)
3. Deploy with Docker Compose or Portainer.
4. Put the service behind HTTPS reverse proxy.
5. Point `autodiscover.` and `autoconfig.` DNS records to that proxy.
6. Test the endpoints before sharing them with users.
### Single-Domain Or Shared Global Config
```env
APP_ENV=production
PUBLIC_BASE_URL=https://autodiscover.example.com
ALLOWED_DOMAINS=example.com,example.org
MAIL_DISPLAY_NAME=Example Mail
MAIL_DISPLAY_SHORT_NAME=Example
IMAP_HOST=mail.example.com
IMAP_PORT=993
IMAP_SOCKET_TYPE=SSL
SMTP_HOST=mail.example.com
SMTP_PORT=587
SMTP_SOCKET_TYPE=STARTTLS
POP3_ENABLED=false
TRUST_PROXY_HEADERS=true
TRUSTED_PROXY_IPS=127.0.0.1,10.0.0.0/8
```
This mode serves the same IMAP/SMTP profile for every domain listed in `ALLOWED_DOMAINS`.
### Multi-Domain Config File
Set:
```env
CONFIG_FILE=/config/config.yaml
```
Then mount a file like [`config/config.example.yaml`](config/config.example.yaml).
If `CONFIG_FILE` exists, domain settings are loaded from YAML and the application ignores the global `ALLOWED_DOMAINS`/`IMAP_*`/`SMTP_*` values for request routing.
`USERNAME_FORMAT` is not per-domain in YAML mode; it still comes from ENV and applies to every configured domain.
## Docker / Portainer
For local builds:
```bash
docker compose up -d
```
For GHCR images:
```bash
docker compose -f docker-compose.ghcr.yml up -d
```
The compose examples mount `./config:/config:ro`, so placing `config/config.yaml` next to the compose file is enough for multi-domain mode.
Prebuilt images are published to GHCR:
```text
ghcr.io/solarssk/mail-autodiscover:latest
ghcr.io/solarssk/mail-autodiscover:0.3.2
```
Prefer pinned tags or digests in production.
## Reverse Proxy Contract
- `TRUST_PROXY_HEADERS=false` is the safe default.
- Enable `TRUST_PROXY_HEADERS=true` only when traffic really arrives through your own proxy.
- In production, `TRUSTED_PROXY_IPS` is required whenever proxy header trust is enabled.
- Thunderbird and Apple Mail use `?emailaddress=user@example.com` in the query string.
Important:
Your reverse proxy may log the full query string even though this application does not. Review access log settings for:
- `/mail/config-v1.1.xml`
- `/.well-known/autoconfig/mail/config-v1.1.xml`
- `/mail/ios.mobileconfig`
- `/.well-known/apple-mail.mobileconfig`
## Endpoints
| Method | Path | Purpose |
|--------|------|---------|
| `GET` | `/health` | Liveness probe |
| `GET` | `/ready` | Readiness probe |
| `GET` | `/` | Minimal landing page |
| `GET` | `/robots.txt` | No-index hint |
| `GET` | `/mail/config-v1.1.xml?emailaddress=...` | Thunderbird Autoconfig |
| `GET` | `/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=...` | Thunderbird alias |
| `GET` | `/mail/ios.mobileconfig?emailaddress=...` | Apple Mail profile |
| `GET` | `/.well-known/apple-mail.mobileconfig?emailaddress=...` | Apple Mail alias |
| `POST` | `/autodiscover/autodiscover.xml` | Outlook Autodiscover |
| `GET` | `/autodiscover/autodiscover.xml` | Neutral Outlook response |
## Apple Mail Notes
- Profiles are unsigned by default.
- iOS and macOS warn about unsigned profiles in self-hosted setups; this is expected.
- Profiles never contain mailbox passwords.
- Re-downloading the same mailbox profile updates the existing profile because identifiers are stable.
- If you need signed profiles, sign them externally before distribution.
## Logging And Observability
- `X-Request-ID` is attached to responses and access logs.
- Access logs never include the full mailbox address.
- `STRUCTURED_JSON_LOGS=true` switches access logging to JSON.
- `/metrics` is intentionally not built in.
## Documentation
- [Reverse Proxy and DNS](docs/dns.md)
- [Nginx](docs/reverse-proxy/nginx.md)
- [Caddy](docs/reverse-proxy/caddy.md)
- [Nginx Proxy Manager](docs/reverse-proxy/nginx-proxy-manager.md)
- [Synology Reverse Proxy](docs/reverse-proxy/synology-reverse-proxy.md)
- [Cloudflare Tunnel / Generic Proxy](docs/reverse-proxy/cloudflare-tunnel.md)
- [Outlook client setup](docs/clients/outlook.md)
- [Thunderbird client setup](docs/clients/thunderbird.md)
- [Apple Mail client setup](docs/clients/apple-mail.md)
- [Troubleshooting](docs/troubleshooting.md)
## Security At A Glance
- no mailbox enumeration
- no full email address logging
- safe XML parsing
- bounded in-memory rate limiting
- security headers enabled by default
- no admin API
See [SECURITY.md](SECURITY.md) for the detailed trust model.
## Local Development
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install ".[dev]"
pre-commit install
cp .env.example .env
uvicorn app.main:app --host 0.0.0.0 --port 8000 --no-access-log --reload
```
For development with placeholder values, set `APP_ENV=test` or `APP_ENV=development`.
## Quality Checks
Run the same Python checks as GitHub CI:
```bash
./scripts/check.sh
```
`pre-commit install` also runs `ruff`, `mypy`, and `pytest` automatically before each commit.
Developer workflow and release process live in [`CONTRIBUTING.md`](CONTRIBUTING.md).