mailcatcher

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2025 License: MIT Imports: 15 Imported by: 0

README

mailcatcher

Test Go Report Card Go Reference License

SMTP mail catcher for testing - works as Go library or standalone server.

Features

  • Dual Mode: Use as Go library or standalone application
  • SMTP Server: Captures emails on port 1025 (configurable)
  • HTTP API: JSON REST API on port 8025 (configurable)
  • Docker Support: Multi-arch images (amd64, arm64)
  • Thread-Safe: Safe for concurrent use
  • Subject Parsing: Extracts email subject from headers
  • CORS Enabled: Ready for web UI integration
  • Zero Config: Works out of the box

Installation

As Go Library
go get github.com/andmetoo/mailcatcher
As Standalone Application

Binary releases:

# Download from GitHub Releases
wget https://github.com/andmetoo/mailcatcher/releases/latest/download/mailcatcher_Linux_x86_64.tar.gz
tar -xzf mailcatcher_Linux_x86_64.tar.gz
./mailcatcher

Using Go:

go install github.com/andmetoo/mailcatcher/cmd/mailcatcher@latest

Using Docker:

docker run -p 1025:1025 -p 8025:8025 ghcr.io/andmetoo/mailcatcher:latest

Using Docker Compose:

docker-compose up

Usage

1. Standalone Application
# Start with default ports (SMTP: 1025, HTTP: 8025)
mailcatcher

# Custom ports
mailcatcher -smtp-port 2525 -http-port 8080

# With verbose logging
mailcatcher -verbose

# Using environment variables
export MAILCATCHER_SMTP_PORT=2525
export MAILCATCHER_HTTP_PORT=8080
mailcatcher

# Show version
mailcatcher -version
2. Go Library (Integration Tests)
package myapp_test

import (
    "testing"
    "net/smtp"
    "github.com/andmetoo/mailcatcher"
)

func TestEmailSending(t *testing.T) {
    // Start default server (ports 1025/8025)
    server, err := mailcatcher.DefaultServer()
    if err != nil {
        t.Fatal(err)
    }
    defer mailcatcher.StopDefault()

    // Clear any existing emails
    server.Clear()

    // Your app sends email to localhost:1025
    smtp.SendMail("localhost:1025", nil,
        "sender@example.com",
        []string{"recipient@example.com"},
        []byte("Subject: Test\r\n\r\nBody"))

    // Check captured emails
    emails := server.Emails()
    if len(emails) != 1 {
        t.Errorf("Expected 1 email, got %d", len(emails))
    }

    if emails[0].Subject != "Test" {
        t.Errorf("Wrong subject: %s", emails[0].Subject)
    }
}
3. Custom Configuration
// Create server with custom ports
server := mailcatcher.New(2525, 8080)
err := server.Start()
if err != nil {
    log.Fatal(err)
}
defer server.Stop(context.Background())

// Use default ports (1025/8025)
server := mailcatcher.NewWithDefaults()

// Enable custom logging
server.SetLogger(log.Default())
4. Programmatic API
// Get all emails
emails := server.Emails()

// Get specific email
email := server.Email("msg-0")
if email != nil {
    fmt.Println(email.Subject)
    fmt.Println(email.From)
    fmt.Println(email.To)
    fmt.Println(email.Body)
}

// Clear all emails
server.Clear()

HTTP API

GET /api/v1/emails

Returns all captured emails.

curl http://localhost:8025/api/v1/emails

Response:

{
  "total": 2,
  "count": 2,
  "items": [
    {
      "id": "msg-0",
      "from": "sender@example.com",
      "to": ["recipient@example.com"],
      "subject": "Test Email",
      "body": "Subject: Test Email\r\n\r\nEmail body...",
      "time": "2025-01-15T10:30:00Z"
    }
  ]
}
GET /api/v1/emails/{id}

Returns specific email by ID.

curl http://localhost:8025/api/v1/emails/msg-0
DELETE /api/v1/emails

Clears all captured emails.

curl -X DELETE http://localhost:8025/api/v1/emails

Environment Variables

# SMTP server port (default: 1025)
MAILCATCHER_SMTP_PORT=1025

# HTTP API server port (default: 8025)
MAILCATCHER_HTTP_PORT=8025

Docker

Standalone Container
docker run -d \
  -p 1025:1025 \
  -p 8025:8025 \
  --name mailcatcher \
  ghcr.io/andmetoo/mailcatcher:latest
Docker Compose
version: '3.8'

services:
  mailcatcher:
    image: ghcr.io/andmetoo/mailcatcher:latest
    ports:
      - "1025:1025"
      - "8025:8025"
    environment:
      - MAILCATCHER_SMTP_PORT=1025
      - MAILCATCHER_HTTP_PORT=8025
    restart: unless-stopped

Email Structure

type Email struct {
    ID      string    `json:"id"`      // Auto-generated: msg-0, msg-1, ...
    From    string    `json:"from"`    // Sender address
    To      []string  `json:"to"`      // Recipient addresses
    Subject string    `json:"subject"` // Parsed from headers
    Body    string    `json:"body"`    // Full email with headers
    Time    time.Time `json:"time"`    // Capture timestamp
}

Use Cases

  • ✅ Integration testing of email-sending code
  • ✅ Local development without real SMTP server
  • ✅ Email preview in development environment
  • ✅ CI/CD pipeline testing
  • ✅ Manual email testing for non-Go projects

Similar Projects

mailcatcher is unique as it works both as a Go library and standalone application.

Development

Using Makefile
# Show all available commands
make help

# Build standalone application
make build

# Run tests
make test

# Run tests with coverage
make test-coverage

# Run linters
make lint

# Format code
make fmt

# Run all checks (tests + lint)
make check

# Run full CI suite locally
make ci

# Build for all platforms
make build-all

# Clean build artifacts
make clean
Manual Build
# Build library
go build ./...

# Build standalone app
go build ./cmd/mailcatcher

# Run tests
go test -v ./...

# Run with coverage
go test -v -coverprofile=coverage.out ./...
Docker Development
# Build Docker image
make docker-build

# Run Docker container
make docker-run

# Start with docker-compose
make docker-compose-up
Release

Releases are automated via GitHub Actions and GoReleaser:

git tag v1.0.0
git push origin v1.0.0

This will:

  • Build binaries for Linux, macOS, Windows (amd64, arm64)
  • Create Docker images for amd64 and arm64
  • Publish to GitHub Releases
  • Push images to GitHub Container Registry

License

MIT License - see LICENSE file.

Author

andmetoo

Contributing

Pull requests welcome! Please ensure:

go test -v ./...          # Tests pass
go build ./...            # Code compiles
golangci-lint run         # Linting passes

Documentation

Overview

Package mailcatcher provides an in-process SMTP mail catcher for Go testing.

It captures emails sent via SMTP and exposes them through both a programmatic API and HTTP endpoints, making it ideal for integration testing of email-sending functionality.

Quick Start

Use DefaultServer() for simple integration testing:

func TestEmailSending(t *testing.T) {
    server, err := mailcatcher.DefaultServer()
    if err != nil {
        t.Fatal(err)
    }
    defer mailcatcher.StopDefault()

    // Your code sends email to localhost:1025
    // ...

    // Check captured emails
    emails := server.Emails()
    if len(emails) != 1 {
        t.Errorf("Expected 1 email, got %d", len(emails))
    }
}

Custom Configuration

Create a server with custom ports:

server := mailcatcher.New(2525, 8080)
if err := server.Start(); err != nil {
    log.Fatal(err)
}
defer server.Stop(context.Background())

Or use default ports (1025 for SMTP, 8025 for HTTP):

server := mailcatcher.NewWithDefaults()

HTTP API

The server exposes a REST API on port 8025 (configurable):

  • GET /api/v1/emails - Returns all captured emails
  • GET /api/v1/emails/{id} - Returns a specific email
  • DELETE /api/v1/emails - Clears all emails

Example:

curl http://localhost:8025/api/v1/emails

Features

  • Thread-safe email storage
  • Subject parsing from email headers
  • CORS-enabled HTTP API
  • Configurable ports
  • Optional custom logging

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func StopDefault

func StopDefault() error

StopDefault stops the global mail catcher server.

Types

type Email

type Email struct {
	ID      string    `json:"id"`
	From    string    `json:"from"`
	Subject string    `json:"subject"`
	Body    string    `json:"body"`
	Time    time.Time `json:"time"`
	To      []string  `json:"to"`
}

Email represents a captured email message.

type Logger

type Logger interface {
	Printf(format string, v ...any)
}

Logger is a simple logging interface.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is an in-process mail catcher for testing.

func DefaultServer

func DefaultServer() (*Server, error)

DefaultServer returns the global mail catcher server or starts it if not running. This is useful for integration tests where you want a shared instance. Ports can be configured via environment variables:

  • MAILCATCHER_SMTP_PORT (default: 1025)
  • MAILCATCHER_HTTP_PORT (default: 8025)

func New

func New(smtpPort, httpPort int) *Server

New creates a new mail catcher server with custom ports.

func NewWithDefaults

func NewWithDefaults() *Server

NewWithDefaults creates a new mail catcher server with default ports. SMTP: 1025, HTTP: 8025

func (*Server) Clear

func (s *Server) Clear()

Clear removes all captured messages.

func (*Server) Email

func (s *Server) Email(id string) *Email

Email returns a specific email by ID. Returns nil if email with given ID is not found.

func (*Server) Emails

func (s *Server) Emails() []Email

Emails returns all captured email messages.

func (*Server) SetLogger

func (s *Server) SetLogger(logger Logger)

SetLogger sets a custom logger for server errors. By default, errors are silently ignored.

func (*Server) Start

func (s *Server) Start() error

Start starts the mail catcher server.

func (*Server) Stop

func (s *Server) Stop(ctx context.Context) error

Stop stops the mail catcher server.

Directories

Path Synopsis
cmd
mailcatcher command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL