# Inbucket: catch-all mail server that keeps mail in memory or on disk

> An SMTP server that accepts mail for any address and hands it back over a web UI, a REST API and POP3, with no database and no external services, aimed squarely at automated testing.

**inbucket/inbucket** — Disposable webmail server (similar to Mailinator) with built in SMTP, POP3, RESTful servers; no DB required.

- Repository: https://github.com/inbucket/inbucket
- Website: https://inbucket.org/
- Stars: 2,305 · Forks: 221
- Language: Go
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/inbucket-inbucket

## One container, three ports, no database

Inbucket accepts messages for any email address and makes them available three ways: a web interface, a REST API and POP3. The design constraint that shapes everything else is stated in the README as the absence of external dependencies. Once compiled, HTTP, SMTP, POP3 and storage are all built in, so there is no database to provision and no mail relay to configure.

The Docker image is the shortest path to a running instance, and the README publishes exactly one command:

```
docker run -d --name inbucket -p 9000:9000 -p 2500:2500 -p 1100:1100 inbucket/inbucket
```

Those three ports map to the three interfaces: 9000 for the web interface, 2500 for SMTP and 1100 for POP3. Point a browser at localhost:9000 and you are looking at the inbox. The image has automated builds on Docker Hub where the `latest` tag tracks tagged releases and `edge` tracks the possibly unstable `main` branch.

The word Inbucket can read like a throwaway address service, and the project description says as much, calling it a disposable webmail server similar to Mailinator. The difference worth noticing is that it is aimed at developers, not at humans wanting a private mailbox. Repository topics include integration-testing and mailserver alongside smtp, pop3 and webmail, and the README describes it as an email testing service.

## Building from source needs both Go and Node.js

The build is two languages, and the README is upfront that you need a functioning Go and a functioning Node.js installation. The sequence is a clone, a frontend build with Yarn, then a Go build:

```sh
git clone https://github.com/inbucket/inbucket.git
cd inbucket/ui
yarn install
yarn build
cd ..
go build ./cmd/inbucket
```

The Node.js step is not incidental. Inbucket is written in Go and Elm, and the Elm frontend lives in the `ui/` directory. This is visible in the Dockerfile, which builds the frontend in a Node 20 stage using `yarn install --frozen-lockfile --non-interactive` and `yarn run build`, then builds the backend in a Go 1.25 Alpine stage. The comment on that first stage explains why it pins the platform: due to no official Elm compiler for arm, build frontend with amd64. If you are on Apple Silicon and building locally, that is the wrinkle to expect.

The Go build is straightforward and produces two binaries. The Makefile defines `commands = client inbucket`, so `make build` produces an `inbucket` server binary and a `client` binary, with a pattern rule that compiles each from `cmd/%`. The release build in the Dockerfile stamps version and date metadata into the binary:

```
RUN go build -o inbucket \
  -ldflags "-X 'main.version=$(git describe --tags --always)' -X 'main.date=$(date -Iseconds)'" \
  -v ./cmd/inbucket
```

Note `CGO_ENABLED=0` in that stage, which is what lets the final image be plain Alpine with no C library needed.

## Configuration is environment variables with working defaults

Inbucket reads configuration from environment variables and ships defaults that the README says should work as is on most Unix and OS X machines. Launching the daemon is `./inbucket`, which gives you SMTP on localhost port 2500 and the web interface on port 9000.

The Dockerfile is the most complete configuration reference in the repository, because it has to set the values that a container cannot infer:

```
ENV INBUCKET_SMTP_DISCARDDOMAINS=bitbucket.local
ENV INBUCKET_SMTP_TIMEOUT=30s
ENV INBUCKET_POP3_TIMEOUT=30s
ENV INBUCKET_WEB_GREETINGFILE=/config/greeting.html
ENV INBUCKET_WEB_COOKIEAUTHKEY=secret-inbucket-session-cookie-key
ENV INBUCKET_WEB_UIDIR=ui
ENV INBUCKET_STORAGE_TYPE=file
ENV INBUCKET_STORAGE_PARAMS=path:/storage
ENV INBUCKET_STORAGE_RETENTIONPERIOD=72h
ENV INBUCKET_STORAGE_MAILBOXMSGCAP=300
```

Several of those deserve a second look. `INBUCKET_STORAGE_TYPE=file` with `INBUCKET_STORAGE_PARAMS=path:/storage` selects the file store and points it at a volume, and `INBUCKET_STORAGE_RETENTIONPERIOD=72h` is what makes a long-running test host safe: messages expire after three days. `INBUCKET_STORAGE_MAILBOXMSGCAP=300` caps messages per mailbox, which is a memory bound on a machine running many suites.

`INBUCKET_SMTP_DISCARDDOMAINS=bitbucket.local` is the setting that makes Inbucket useful in mixed environments, since a domain on that list is silently dropped instead of being stored. `INBUCKET_WEB_COOKIEAUTHKEY` is set to a literal placeholder in the image, which is fine for a local run and wrong for a shared host, so treat it as something to change rather than something to copy.

The README points at `doc/config.md` for the full list and mentions a Configurator tool hosted at inbucket.org as the easiest way to generate a configuration.

## Go clients, Lua hooks and what the go.mod reveals

Three integrations are worth knowing about before you decide how to drive Inbucket from a test.

First, there is a Go client for the REST API at `github.com/inbucket/inbucket/pkg/rest/client`, with API docs on pkg.go.dev. Recent release notes show it has been actively improved rather than left as an afterthought: v3.1.0-beta3 added context support for the REST client and allowed relative URLs.

Second, Inbucket has Lua scripting on the SMTP path, which is how you make assertions or side effects at the moment a message is accepted rather than polling afterwards. The `yuin/gopher-lua` dependency is what provides that, and the 3.1.0-beta3 release added an `SMTPSession` type and a `BeforeRcptToAccepted` event, exposed `RemoteAddr` on `SMTPSession`, and added an `SMTPResponse` type for extensions. It also renamed the Lua `BeforeMailAccepted` hook and changed its arguments, which is a breaking change for anyone on an older beta, and v3.1.0 added a log note that a missing Lua script is not an error.

Third, the dependency list in `go.mod` shows the mail handling is done properly rather than with a naive parser. `jhillyerd/enmime/v2` handles MIME multipart messages, `microcosm-cc/bluemonday` sanitizes HTML, `inbucket/html2text` produces the plain-text alternative, `rs/zerolog` is the logger, `gorilla/mux` and `gorilla/websocket` serve the web interface including its live updates, and `kelseyhightower/envconfig` is the environment configuration binding.

The `cosmotek/loguago` and `cjoudrey/gluahttp` dependencies are for logging through Lua and making HTTP calls from scripts, and `inbucket/gopher-json` is a fork of encoding/json. The project maintains its own forks of enmime and html2text, which tells you it has needed upstream changes and carries the maintenance burden.

## Maintenance status, releases and the honest gaps

The README makes a direct claim about maturity: Inbucket is currently production quality, and it is being used for real work. The repository has 2,305 stars, 221 forks and 32 open issues, is MIT licensed, is not archived, and the last push was on 2026-09-21.

The release cadence is slow and deliberate. v3.1.1 came on 2025-12-06 and is a security and housekeeping release: a Go version update for CVE-2025-47907 and removal of a broken Windows arm7 build. v3.1.0 on 2025-07-27 added the missing-Lua-script log note and fixed handling of mail sent with an empty 821.From envelope sender, which is the sort of RFC detail that breaks a real integration. The prior v3.1.0-beta3 from 2024-11-02 is where most of the work sits, including the Lua additions above, a fix preventing STLS command crashes in POP3, and a date-format fix for the Yarn build.

Two gaps are visible in the repository itself. The root still carries a Travis CI build status badge pointing at travis-ci.org while the actual badges at the top of the README are GitHub Actions for build and test and for the Docker image, so the build has moved and one badge was left behind. And the Makefile's lint target still calls `golint`, which is deprecated, alongside gofmt and go vet, even though `.golangci.yml` sits in the tree as the modern configuration. Neither affects users, both suggest local tooling has not tracked the CI migration.

There is also an `AGENTS.md` in the tree, which usually means the project documents conventions for automated contributors, and a `shell.nix` for Nix users. Configuration depth beyond the Dockerfile defaults is in `doc/config.md`, and the wiki's Development Quickstart page covers build and development flows.

## Conclusion

Inbucket is at its best as a fixture in an automated test suite, where the cost that matters is the one it removes: a real mail provider, real domains and the flakiness of asserting on outbound mail. Its zero-dependency design, its three interfaces over the same store and its Lua hooks for SMTP events are what make it more than a Mailinator clone, and the Dockerfile already sets a sane retention window of 72 hours so you are not obliged to think about cleanup. Start with the single docker run command, then read doc/config.md for the storage and web settings, because the defaults are tuned for local use and a shared CI host will want the retention period and the session cookie key changed.

## FAQ

### What is Inbucket used for?

It is an email testing service. It accepts mail for any address over SMTP and makes the messages available over a web interface, a REST API and POP3, so an application under test can send a real message and then read it back without a real mail provider. Repository topics list integration-testing alongside the mail protocols, which points at automated test suites as the main use.

### Does Inbucket need a database?

No. The README states that once compiled, Inbucket has no external dependencies, with HTTP, SMTP, POP3 and storage all built in. Storage is selected by configuration, and the Docker image uses the file store with a 72 hour retention period and a 300 message cap per mailbox.

### How do you configure Inbucket?

Environment variables, with defaults that work on most Unix and OS X machines. Prefixes are grouped by subsystem, such as `INBUCKET_SMTP_TIMEOUT`, `INBUCKET_POP3_TIMEOUT`, `INBUCKET_WEB_COOKIEAUTHKEY` and `INBUCKET_STORAGE_RETENTIONPERIOD`. The Dockerfile sets a full working set, and doc/config.md plus the Configurator tool at inbucket.org cover the rest.

### What ports does Inbucket use and how do I run it with Docker?

Port 9000 for the web interface, 2500 for SMTP and 1100 for POP3. The README's command is `docker run -d --name inbucket -p 9000:9000 -p 2500:2500 -p 1100:1100 inbucket/inbucket`, after which you open localhost:9000 in a browser. The Dockerfile exposes the same three ports.

### Can I script Inbucket to react to incoming mail?

Yes, through Lua scripting on the SMTP path, provided by the gopher-lua dependency. Recent releases added an SMTPSession type, a BeforeRcptToAccepted event and an SMTPResponse type for extensions. Be aware that the BeforeMailAccepted hook was renamed and its arguments changed in 3.1.0-beta3, which breaks scripts written against older betas.

## Sources

- [inbucket/inbucket on GitHub](https://github.com/inbucket/inbucket)
- [License: MIT](https://github.com/inbucket/inbucket/blob/main/LICENSE)
- [Project website](https://inbucket.org/)
- [README](https://github.com/inbucket/inbucket/blob/main/README.md)
- [Releases](https://github.com/inbucket/inbucket/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/inbucket-inbucket
