* fix(rest): make WebSocket monitor listener teardown safe under concurrency The commit-1 tests and race detector exposed three related defects in the monitor listener's Close, whose check-then-act select was unsound: 1. With a full event queue (a slow or disconnecting client), the `case <-ml.c:` branch received a buffered event, mistook it for the closed-channel signal, and skipped both RemoveListener and close: the listener stayed registered, and the hub actor then blocked forever inside Receive on the next dispatch, wedging every hub consumer. 2. The read and write pumps both call Close when the connection drops; two callers could pass the select's default branch together and the second close panicked with "close of closed channel". 3. Even made exactly-once, closing the event queue was still unsafe: RemoveListener returns once its op is queued, not processed, so the hub actor could be mid-send into the queue when Close closed it (send on closed channel panic inside the actor). Fix: Close deregisters and closes a `done` channel via sync.Once; the event queue is never closed. Receive and Delete select their enqueue against done and return errListenerClosed when aborted, so the hub removes the listener itself even if RemoveListener has not run yet, and a blocked enqueue aborts instead of wedging the actor. The write pump exits on done and sends the closing frame. Each defect has a regression test that fails against the previous code (verified: no-op close delivered post-close events, concurrent closes panicked, and close raced the actor's blocked send). The write pump keeps its c-close branch for safety; the black-box monitor tests from commit 1 pass unchanged. * fix(rest): close listener done channel before enqueueing removal Copilot review on PR #623 correctly identified a remaining deadlock in msgListener.Close: when the hub actor is blocked inside this listener's Receive (full event queue) and the hub op queue is also full, RemoveListener cannot enqueue, so execution never reached close(ml.done) -- the only operation able to release the actor. Under the same slow-client condition, concurrent dispatchers keeping the hub queue saturated made Close hang permanently. Fix: close the done channel (guarded by the existing sync.Once) before queueing the RemoveListener op. The blocked actor is released first, keeps draining the op queue, and the removal can then be queued even when the queue is full. As a side effect, a Close racing a not-yet-processed AddListener now also deregisters correctly, since the removal op can no longer be overtaken by the earlier registration op. Regression test TestMsgListenerCloseFullHubOpQueue wedges the actor in Receive with a saturated op queue before calling Close; verified it fails ("Close deadlocked") against the previous ordering and passes with -race after the fix, along with the full pkg/rest and pkg/msghub suites.
Inbucket
Inbucket is an email testing service; it will accept messages for any email address and make them available via web, REST and POP3 interfaces. Once compiled, Inbucket does not have any external dependencies - HTTP, SMTP, POP3 and storage are all built in.
A Go client for the REST API is available in
github.com/inbucket/inbucket/pkg/rest/client - Go API docs
Read more at the Inbucket Website
Development Status
Inbucket is currently production quality: it is being used for real work.
Please see the Change Log and Issues List for more details. If you'd like to contribute code to the project check out CONTRIBUTING.md.
Docker
Inbucket has automated Docker Image builds via Docker Hub. The latest tag
tracks our tagged releases, and edge tracks our potentially unstable
main branch.
Start the docker image by running:
docker run -d --name inbucket -p 9000:9000 -p 2500:2500 -p 1100:1100 inbucket/inbucket
Then point your browser to localhost:9000
Building from Source
You will need functioning Go and Node.js installations for this to work.
git clone https://github.com/inbucket/inbucket.git
cd inbucket/ui
yarn install
yarn build
cd ..
go build ./cmd/inbucket
For more information on building and development flows, check out the Development Quickstart page of our wiki.
Configure and Launch
Inbucket reads its configuration from environment variables, but comes with reasonable defaults built-in. It should work on most Unix and OS X machines as is. Launch the daemon:
./inbucket
By default the SMTP server will be listening on localhost port 2500 and the web interface will be available at localhost:9000.
See doc/config.md for more information on configuring Inbucket, but you will likely find the Configurator tool the easiest way to generate a configuration.
About
Inbucket is written in Go and Elm.
Inbucket is open source software released under the MIT License. The latest version can be found at https://github.com/inbucket/inbucket
