1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 01:27:01 +00:00
Files
go-inbucket/AGENTS.md
James Hillyerd be7d29c5d5 chore: Central go-version for GitHub actions (#591)
* chore: Init AGENTS.md

Signed-off-by: James Hillyerd <james@hillyerd.com>

* chore: Central go-version for GitHub actions

Signed-off-by: James Hillyerd <james@hillyerd.com>

---------

Signed-off-by: James Hillyerd <james@hillyerd.com>
2025-12-06 12:45:11 -08:00

8.0 KiB

AGENTS.md - Inbucket

Guidance for AI agents working in this codebase.

Project Overview

Inbucket is an email testing service that accepts messages for any email address and makes them available via web, REST, and POP3 interfaces. It's a self-contained Go application with an Elm-based web UI.

Tech Stack:

  • Backend: Go 1.25+
  • Frontend: Elm 0.19.1 with Parcel bundler
  • Logging: zerolog
  • Testing: testify (assert/require/suite), goldiff for golden file tests
  • HTTP Router: gorilla/mux
  • Configuration: envconfig (environment variables)
  • Optional: Lua scripting for extensions (gopher-lua)

Essential Commands

Build

# Build Go binaries (inbucket server + client CLI)
make build

# Or build directly
go build ./cmd/inbucket
go build ./cmd/client

# Build UI (required before running server)
cd ui && yarn install && yarn build

Test

# Run all Go tests with race detection
make test
# or
go test -race ./...

# Run tests for a specific package
go test -race ./pkg/storage/...

# Run tests with coverage
go test -race -coverprofile=profile.cov ./...

Lint

# CI uses golangci-lint
golangci-lint run

# Make's lint target (older, uses golint)
make lint

Run Development Server

# Build everything first
make build
cd ui && yarn build && cd ..

# Run with dev config
./etc/dev-start.sh

# Or run directly with defaults
./inbucket

Default ports:

UI Development

cd ui

# Install dependencies
yarn install

# Development server with HMR (proxies to Go backend)
yarn start

# Production build
yarn build

# Clean build artifacts
yarn clean

Code Organization

cmd/
  inbucket/           # Main server binary
  client/             # CLI client for REST API

pkg/
  config/             # Environment-based configuration
  extension/          # Lua extension system
    luahost/          # Lua VM pool and bindings
    event/            # Extension event types
  message/            # Message manager (storage abstraction)
  metric/             # Expvar metrics
  msghub/             # Real-time message pub/sub
  policy/             # Email address/domain policies
  rest/               # REST API v1/v2 controllers
    client/           # Go client library for REST API
    model/            # JSON API models
  server/
    smtp/             # SMTP server
    pop3/             # POP3 server
    web/              # HTTP server, handlers, helpers
  storage/            # Storage interface and implementations
    file/             # File-based storage
    mem/              # In-memory storage
  stringutil/         # String utilities
  test/               # Test utilities and integration tests
  webui/              # Web UI controllers

ui/
  src/
    Main.elm          # Elm app entry point
    Api.elm           # API client
    Page/             # Page modules (Home, Mailbox, Monitor, Status)
    Data/             # Data models
  tests/              # Elm tests

Configuration

Inbucket uses environment variables for all configuration. Key variables:

Variable Default Description
INBUCKET_LOGLEVEL info debug, info, warn, error
INBUCKET_MAILBOXNAMING local local, full, or domain
INBUCKET_SMTP_ADDR 0.0.0.0:2500 SMTP listen address
INBUCKET_WEB_ADDR 0.0.0.0:9000 HTTP listen address
INBUCKET_POP3_ADDR 0.0.0.0:1100 POP3 listen address
INBUCKET_STORAGE_TYPE memory memory or file
INBUCKET_WEB_UIDIR ui/dist Path to built UI files

Run ./inbucket -help for complete list.

See doc/config.md for detailed documentation.

Code Patterns

Error Handling

  • Use zerolog for structured logging
  • Return errors up the call stack; log at the top level
  • Use github.com/pkg/errors patterns for wrapping

HTTP Handlers

Handlers follow this pattern in pkg/server/web/:

func Handler(f func(http.ResponseWriter, *http.Request, *Context) error) http.Handler

Controllers return errors; the wrapper handles HTTP responses.

Storage Interface

New storage backends implement storage.Store interface (pkg/storage/storage.go):

type Store interface {
    AddMessage(message Message) (id string, err error)
    GetMessage(mailbox, id string) (Message, error)
    GetMessages(mailbox string) ([]Message, error)
    MarkSeen(mailbox, id string) error
    PurgeMessages(mailbox string) error
    RemoveMessage(mailbox, id string) error
    VisitMailboxes(f func([]Message) (cont bool)) error
}

Register in cmd/inbucket/main.go init():

storage.Constructors["mytype"] = mystore.New

JSON Tag Convention

JSON fields use kebab-case (configured in .golangci.yml tagliatelle):

type Example struct {
    FieldName string `json:"field-name"`
}

Elm Architecture

The UI follows The Elm Architecture:

  • Main.elm - App shell, routing
  • Page/*.elm - Page modules with Model, Msg, init, update, view
  • Data/*.elm - Data types and JSON decoders
  • Api.elm - HTTP client for REST API

Testing

Test Structure

  • Unit tests: alongside source files (*_test.go)
  • Integration tests: pkg/test/integration_test.go
  • Test utilities: pkg/test/

Test Frameworks

  • Standard testing package
  • github.com/stretchr/testify/assert - assertions
  • github.com/stretchr/testify/require - fatal assertions
  • github.com/stretchr/testify/suite - test suites
  • github.com/jhillyerd/goldiff - golden file testing

Test Utilities

Located in pkg/test/:

  • StoreStub, ManagerStub - mock implementations
  • DeliverToStore() - create test messages
  • StoreSuite() - table-driven storage tests
  • NewLuaState() - Lua testing helper

Golden File Tests

Input in pkg/test/testdata/*.txt, expected output in *.golden:

goldiff.File(t, got, "testdata", "basic.golden")

Running Specific Tests

# Run tests matching pattern
go test -race -run TestIntegration ./pkg/test/

# Run with verbose output
go test -race -v ./pkg/storage/mem/

# Run storage suite for specific implementation
go test -race -run TestMemStore ./pkg/storage/mem/

CI/CD

GitHub Actions workflows in .github/workflows/:

  • build-and-test.yml - Build and test on Linux/Windows, coverage to coveralls
  • lint.yml - golangci-lint
  • docker-build.yml - Docker image builds
  • release.yml - goreleaser for releases

Important Gotchas

  1. UI must be built before running server - The Go server serves static files from ui/dist/

  2. Storage type affects persistence - memory storage loses all data on restart; use file for persistence

  3. Port conflicts - Default ports (9000, 2500, 1100) may conflict with other services

  4. Lua scripting is optional - If inbucket.lua is not present, the server runs without extensions

  5. Test coverage requires race detector - CI always runs with -race

  6. golangci-lint v2 config - Uses v2 format in .golangci.yml

  7. Windows paths in storage - Use $ instead of : in file storage paths (e.g., D$/inbucket)

REST API

Base URL: http://localhost:9000/api/

API v1 Endpoints

  • GET /v1/mailbox/{name} - List messages
  • GET /v1/mailbox/{name}/{id} - Get message
  • PATCH /v1/mailbox/{name}/{id} - Mark as seen
  • DELETE /v1/mailbox/{name} - Purge mailbox
  • DELETE /v1/mailbox/{name}/{id} - Delete message
  • GET /v1/mailbox/{name}/{id}/source - Get raw source

API v2 Endpoints

  • GET /v2/monitor/messages - WebSocket for real-time messages

Go client available: github.com/inbucket/inbucket/v3/pkg/rest/client

Development Tips

  1. Quick iteration - Use make reflex for auto-rebuild on Go file changes

  2. UI development - Run yarn start in ui/ for HMR; it proxies API requests to the Go server

  3. Debug network - Run with -netdebug flag to dump SMTP/POP3 traffic

  4. Test email sending - Use swaks or the test scripts in etc/swaks-tests/

  5. Check configuration - Run ./inbucket -help to see all env vars and defaults