Skip to content

Migrate mail service from Docker to native Mailpit binary#61

Merged
munezaclovis merged 5 commits intomainfrom
feat/mailpit-native-binary
Apr 15, 2026
Merged

Migrate mail service from Docker to native Mailpit binary#61
munezaclovis merged 5 commits intomainfrom
feat/mailpit-native-binary

Conversation

@munezaclovis
Copy link
Copy Markdown
Contributor

@munezaclovis munezaclovis commented Apr 15, 2026

Summary

  • Replaces the Docker-based mail service (axllent/mailpit:latest container) with the upstream Mailpit binary, supervised by the pv daemon via the BinaryService infrastructure built for RustFS.
  • Preserves the existing contract: service name "mail", SMTP/HTTP ports 1025/8025, WebRoute{mail, 8025}, and the MAIL_* env var keys/values — linked Laravel projects keep working with zero .env rewrites (pinned via golden test).
  • Uses the HTTP /livez ready-probe branch of BinaryService.ReadyCheck for the first time (rustfs uses TCP), closing the remaining untested code path in the supervisor wiring.

Five commits:

  1. binaries.Mailpit descriptor + installMailpit (tar.gz download + extract + chmod).
  2. Mailpit struct implementing BinaryService, registered as "mail".
  3. Delete Docker Mail struct + its tests; "mail" is now binary-only.
  4. E2E lifecycle script (add/livez:1025stopstartdestroy) wired into CI as Phase 21.
  5. Address PR review: surface previously-swallowed errors in destroy.go/remove.go, pin bind addresses in the Args test, polish comments.

Test plan

  • go build ./... / go vet ./... / go test ./... (28 packages passing locally)
  • CI Phase 21 scripts/e2e/mail-binary.sh exercises: service:add mail, binary present + executable, daemon-status.json lists mailpit, HTTP /livez 200, TCP 1025 reachable, service:stop stops it, service:start restarts it, service:destroy removes binary + data dir.
  • Manual smoke test: upgrade an existing pv install with a Docker-shaped mail entry → resolveKind errors with the "run pv uninstall && pv setup to reset" remedy (no silent auto-migration).
  • Verify linked Laravel projects still send mail after pv service:add mail.env keys unchanged, SMTP listens on 1025.

Known deferred work (not regressions from this PR — all pre-existing from rustfs)

Pre-existing callsites that only consult the Docker registry and silently mishandle any registered binary service. Mail now inherits these gaps:

  • cmd/setup.go — mail disappears from the wizard checkbox list and is not installed by the post-wizard loop.
  • internal/commands/service/env.gopv service:env mail prints "Skipping unknown service" / errors out.
  • cmd/doctor.go — reports a healthy mail as "unknown service type — registry may be out of date".

These are best closed in a dedicated follow-up PR that introduces a services.LookupAny(name) helper, so the fix lands in one place rather than four.

Also deferred: tightening ReadyCheck into a proper sum type (TCPReady / HTTPReady constructors), adding TestBuildSupervisorProcess_Mailpit, and extending the E2E to assert linked-project .env injection.

Mirrors the Mago pattern: .tar.gz download + ExtractTarGz + chmod.
Wired into InstallBinary via a new mailpit case. Not added to
Tools() because Mailpit is a backing service, not a CLI tool.
Mailpit registers itself as "mail" in the binary registry. Uses
the HTTP ReadyCheck variant pointing at /livez — the first user of
the HTTP probe since RustFS uses TCP. EnvVars keys/values are pinned
against the current Docker Mail service so linked projects do not
need .env rewrites after the migration.

Also deduplicates Available() so "mail" is not double-counted while
both Docker registry and binaryRegistry carry the key during migration
(Task 4 will remove the Docker side).
The Mailpit BinaryService registered itself as "mail" in Task 3;
the Docker Mail struct is removed along with its tests. The Docker
registry map no longer contains mail. No other code changes needed
because the service:* command dispatcher (from the rustfs plan)
already routes "mail" to the binary path via resolveKind.
Mirrors the rustfs E2E: service:add, stop, start, destroy. Uses
curl on /livez rather than nc, exercising the HTTP ReadyCheck path
for the first time in CI.
…mments

- destroy.go + remove.go: stop swallowing errors on os.Remove, LoadVersions,
  vs.Save, and SignalDaemon (destroy.go only — remove.go already logged it);
  surface them via ui.Subtle so stale versions-manifest state or left-behind
  binaries are visible to the user instead of silent.
- TestMailpit_Args_PinsBindAddresses: new test pinning --smtp :1025 and
  --listen :8025 to catch port/Args drift against Port / ConsolePort / the
  EnvVars golden map.
- mailpit.go: doc comment explaining the deliberate Mailpit→"mail" naming
  mismatch (preserves the old Docker service key); removed "Task 1" reference
  and added a note on /livez; documented init() self-registration.
- service.go: rephrased Available() dedup comment without transient
  "during migration" language.
@munezaclovis munezaclovis merged commit 4a432f8 into main Apr 15, 2026
1 check failed
@munezaclovis munezaclovis deleted the feat/mailpit-native-binary branch April 15, 2026 06:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant