BearerMail docs

Troubleshooting

The failures that have actually happened, and the smallest thing that fixes each one.

Mail isn't arriving

  1. Is port 25 reachable? From outside your network: telnet mail.yourdomain.com 25 should show the Postfix banner. If it hangs, your ISP or host is blocking inbound port 25 — you can't receive directly.
  2. Is the MX right? dig MX yourdomain.com should point at your mail hostname, and that A record must be DNS-only (grey cloud), not proxied.
  3. Watch the conversation: docker compose logs -f mta shows every SMTP session live.

Log lines worth knowing:

  • NOQUEUE: reject: RCPT ... Relay access denied — the recipient isn't in MAIL_ACCOUNTS.
  • status=bounced with a DNS error — the container can't resolve; check the host's DNS.

Mail goes to spam / gets rejected

  • Check the triad: SPF, DKIM and DMARC all published and valid? Use the admin DNS checker or an external validator (e.g. mail-tester.com).
  • PTR record: no reverse DNS on your IP is the most common reason Gmail distrusts a new server.
  • Home IP? Stop delivering directly and relay through Mailjet — Sending: direct or relayed.
  • New domain? Fresh domains have no reputation. Warm up with real correspondence before any volume.

A container is restart-looping

The app containers run database migrations on every boot. A failing migration restart-loops the container:

docker compose logs php | tail -40   # or worker / scheduler / imap-supervisor

Look for the migration error at the top of the loop. Common cause: a non-idempotent migration replayed against a partially-migrated database. Fix the migration to be idempotent (CREATE TABLE IF NOT EXISTS, guarded ALTERs), then rebuild all four app services — they share one image:

docker compose --profile mail up -d --build
Rebuild everything, not one service

All app services share the plmail-fork:latest image. Rebuilding only php leaves the others on the old image with the old bug.

Relay stopped working

  • Check Admin → Mail server: is the relay still configured, or did someone clear the host field (which reverts to direct delivery)?
  • Remember: MAIL_RELAY* env vars override the UI. If you set them in the shell and forgot, the UI can't change them.
  • Mailjet secret rotated? Update it in the same place you set it.

Android app won't pair / sync

  • Auth proxy in front? The app needs a direct path to the server — bypass forward-auth (Authentik etc.) for the mail hostname.
  • "Scan the code" closes the app or says the camera could not be started: update to 0.0.33 or later (the scanner uses ZXing instead of ML Kit). Meanwhile use Enter the address instead. Check that Android's Camera access quick-settings toggle is on.
  • No update offered: the app checks at most once an hour. Use Drawer → Check for updates, or fully close and reopen the app.
  • Signed out after reinstalling: expected. Updates keep the login; uninstalling or Clear storage removes it. Pair again.
  • App closed unexpectedly: reopen it, tap Copy on the crash report and include it in a GitHub issue.
  • Release workflow fails with No key with alias … found in keystore: the KEY_ALIAS secret must contain only the alias word (check with keytool -list), then re-run the Release workflow.
  • Updates failing to install: every APK must be signed with the same key. If you installed a debug build or a differently-signed APK, uninstall first — Android won't let a mismatched signature update in place.

Share links don't work

  • Check the link hasn't expired — expiries are enforced server-side.
  • If the share page loads but download fails, check the php container's logs and that /app/var/uploads/drive is writable and has disk space.

Still stuck

Collect docker compose logs --tail=100 <service> for the failing service and open an issue on the relevant repo — server or android. Say what you expected, what happened, and what the logs show.