{"id":31028465,"url":"https://github.com/codelieutenant/mailpitclient","last_synced_at":"2025-09-13T20:59:47.630Z","repository":{"id":314082878,"uuid":"1051806520","full_name":"CodeLieutenant/mailpitclient","owner":"CodeLieutenant","description":null,"archived":false,"fork":false,"pushed_at":"2025-09-10T10:43:52.000Z","size":169,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-09-10T14:14:35.635Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CodeLieutenant.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-06T18:57:24.000Z","updated_at":"2025-09-10T10:43:50.000Z","dependencies_parsed_at":"2025-09-10T14:26:23.268Z","dependency_job_id":null,"html_url":"https://github.com/CodeLieutenant/mailpitclient","commit_stats":null,"previous_names":["codelieutenant/mailpitclient"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/CodeLieutenant/mailpitclient","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeLieutenant%2Fmailpitclient","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeLieutenant%2Fmailpitclient/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeLieutenant%2Fmailpitclient/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeLieutenant%2Fmailpitclient/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CodeLieutenant","download_url":"https://codeload.github.com/CodeLieutenant/mailpitclient/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CodeLieutenant%2Fmailpitclient/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275026586,"owners_count":25392763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-13T02:00:10.085Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-13T20:59:44.355Z","updated_at":"2025-09-13T20:59:47.614Z","avatar_url":"https://github.com/CodeLieutenant.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mailpit Go API Client\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/CodeLieutenant/mailpitclient.svg)](https://pkg.go.dev/github.com/CodeLieutenant/mailpitclient)\n[![Go Report Card](https://goreportcard.com/badge/github.com/CodeLieutenant/mailpitclient)](https://goreportcard.com/report/github.com/CodeLieutenant/mailpitclient)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![codecov](https://codecov.io/gh/CodeLieutenant/mailpitclient/graph/badge.svg?token=lqhmgWPlWJ)](https://codecov.io/gh/CodeLieutenant/mailpitclient)\n\n\nA **production-ready** Go client library for the [Mailpit](https://mailpit.axllent.org/) API, providing 100% coverage of all Mailpit API endpoints. Mailpit is a popular email testing tool with a REST API for managing emails, messages, tags, and server operations.\n\n## ✨ Features\n\n- 🚀 **Production-ready** with comprehensive error handling and retry logic\n- 📡 **100% API coverage** - All Mailpit endpoints implemented and tested\n- 🔄 **Context support** for cancellation and timeouts\n- 🔒 **TLS/HTTPS support** with mkcert integration for testing\n- ⚡ **High performance** with connection pooling and optimizations\n- 🧪 **Comprehensive testing** with unit tests and E2E testing via testcontainers\n- 🔧 **Thread-safe** - Safe for concurrent use across goroutines\n- 📚 **Well-documented** with extensive examples and godoc comments\n\n## 📋 Requirements\n\n- Go 1.25.0 or later\n- Mailpit server (for testing/production use)\n\n## 🚀 Installation\n\n```bash\ngo get github.com/CodeLieutenant/mailpitclient\n```\n\n## 🏃 Quick Start\n\n### Basic Usage\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n\n    mailpit \"github.com/CodeLieutenant/mailpitclient\"\n)\n\nfunc main() {\n    // Create client with default configuration (localhost:8025)\n    client, err := mailpit.NewClient(nil)\n    if err != nil {\n        log.Fatal(err)\n    }\n    defer client.Close()\n\n    ctx := context.Background()\n\n    // Check server health\n    if err := client.HealthCheck(ctx); err != nil {\n        log.Fatal(\"Mailpit server not accessible:\", err)\n    }\n\n    // Get server information\n    info, err := client.GetServerInfo(ctx)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Connected to Mailpit v%s\\n\", info.Version)\n\n    // List all messages\n    messages, err := client.ListMessages(ctx, nil)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Found %d messages\\n\", messages.Total)\n}\n```\n\n### Custom Configuration\n\n```go\nconfig := \u0026mailpit.Config{\n    BaseURL:    \"https://mailpit.example.com\",\n    Timeout:    30 * time.Second,\n    MaxRetries: 3,\n    RetryDelay: 1 * time.Second,\n    APIKey:     \"your-api-key\", // For authenticated instances\n}\n\nclient, err := mailpit.NewClient(config)\nif err != nil {\n    log.Fatal(err)\n}\ndefer client.Close()\n```\n\n## 📖 Usage Examples\n\n### Message Operations\n\n#### List Messages with Pagination\n\n```go\nopts := \u0026mailpit.ListOptions{\n    Start: 0,\n    Limit: 10,\n}\nmessages, err := client.ListMessages(ctx, opts)\nif err != nil {\n    log.Fatal(err)\n}\n\nfor _, msg := range messages.Messages {\n    fmt.Printf(\"ID: %s, Subject: %s, From: %s\\n\",\n        msg.ID, msg.Subject, msg.From.Address)\n}\n```\n\n#### Get Message Details\n\n```go\nmessage, err := client.GetMessage(ctx, \"message-id\")\nif err != nil {\n    log.Fatal(err)\n}\n\nfmt.Printf(\"Subject: %s\\n\", message.Subject)\nfmt.Printf(\"From: %s \u003c%s\u003e\\n\", message.From.Name, message.From.Address)\nfmt.Printf(\"Date: %s\\n\", message.Date.Format(time.RFC3339))\nfmt.Printf(\"HTML Body: %s\\n\", message.HTML)\nfmt.Printf(\"Text Body: %s\\n\", message.Text)\n```\n\n#### Search Messages\n\n```go\n// Search by sender email\nresults, err := client.SearchMessages(ctx, \"from:test@example.com\", nil)\nif err != nil {\n    log.Fatal(err)\n}\n\n// Search with additional options\nsearchOpts := \u0026mailpit.SearchOptions{\n    Start: 0,\n    Limit: 20,\n}\nresults, err = client.SearchMessages(ctx, \"subject:important\", searchOpts)\nif err != nil {\n    log.Fatal(err)\n}\n\nfmt.Printf(\"Found %d matching messages\\n\", results.Total)\n```\n\n#### Message Analysis\n\n```go\n// HTML validation\nhtmlCheck, err := client.GetMessageHTMLCheck(ctx, \"message-id\")\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"HTML errors: %d, warnings: %d\\n\",\n    len(htmlCheck.Errors), len(htmlCheck.Warnings))\n\n// Link validation\nlinkCheck, err := client.GetMessageLinkCheck(ctx, \"message-id\")\nif err != nil {\n    log.Fatal(err)\n}\nfor _, link := range linkCheck.Links {\n    fmt.Printf(\"URL: %s, Status: %d, Valid: %v\\n\",\n        link.URL, link.Status, link.Valid)\n}\n\n// SpamAssassin analysis\nsaCheck, err := client.GetMessageSpamAssassinCheck(ctx, \"message-id\")\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Spam score: %.2f, Required: %.2f\\n\",\n    saCheck.Score, saCheck.RequiredScore)\n```\n\n### Send Operations\n\n```go\nmessage := \u0026mailpit.SendMessageRequest{\n    From: mailpit.Address{\n        Address: \"sender@example.com\",\n        Name:    \"Test Sender\",\n    },\n    To: []mailpit.Address{\n        {Address: \"recipient@example.com\", Name: \"Test Recipient\"},\n    },\n    Cc: []mailpit.Address{\n        {Address: \"cc@example.com\", Name: \"CC Recipient\"},\n    },\n    Subject: \"Test Message from Go Client\",\n    HTML:    \"\u003ch1\u003eHello World\u003c/h1\u003e\u003cp\u003eThis is a \u003cstrong\u003etest\u003c/strong\u003e message.\u003c/p\u003e\",\n    Text:    \"Hello World\\n\\nThis is a test message.\",\n    Tags:    []string{\"test\", \"automated\", \"go-client\"},\n}\n\nresult, err := client.SendMessage(ctx, message)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Message sent with ID: %s\\n\", result.ID)\n```\n\n### Tag Operations\n\n```go\n// Get all available tags\ntags, err := client.GetTags(ctx)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Available tags: %v\\n\", tags)\n\n// Set global tags\nnewTags := []string{\"important\", \"test\", \"automated\", \"production\"}\nupdatedTags, err := client.SetTags(ctx, newTags)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Updated global tags: %v\\n\", updatedTags)\n\n// Tag specific messages\nmessageIDs := []string{\"msg-1\", \"msg-2\", \"msg-3\"}\nerr = client.SetMessageTags(ctx, \"urgent\", messageIDs)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Println(\"Messages tagged as 'urgent'\")\n\n// Delete a tag\nerr = client.DeleteTag(ctx, \"old-tag\")\nif err != nil {\n    log.Fatal(err)\n}\n```\n\n### Server Operations\n\n```go\n// Get comprehensive server information\ninfo, err := client.GetServerInfo(ctx)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Mailpit Version: %s\\n\", info.Version)\nfmt.Printf(\"Database: %s\\n\", info.Database)\n\n// Get server statistics\nstats, err := client.GetStats(ctx)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Total messages: %d\\n\", stats.Total)\nfmt.Printf(\"Unread messages: %d\\n\", stats.Unread)\n\n// Get Web UI configuration\nwebConfig, err := client.GetWebUIConfig(ctx)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Read-only mode: %v\\n\", webConfig.ReadOnly)\nfmt.Printf(\"SMTP server enabled: %v\\n\", webConfig.SMTPEnabled)\n```\n\n### Advanced Features\n\n#### Message Release (SMTP Relay)\n\n```go\nreleaseReq := \u0026mailpit.ReleaseMessageRequest{\n    To:   []string{\"recipient@production.com\"},\n    Host: \"smtp.gmail.com\",\n    Port: 587,\n    Auth: \u0026mailpit.SMTPAuth{\n        Username: \"your-email@gmail.com\",\n        Password: \"app-password\",\n        AuthType: \"PLAIN\",\n    },\n    TLS: true,\n}\n\nerr := client.ReleaseMessage(ctx, \"message-id\", releaseReq)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Println(\"Message released via SMTP\")\n```\n\n#### Chaos Testing (for resilience testing)\n\n```go\n// Get current chaos configuration\nchaosConfig, err := client.GetChaosConfig(ctx)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Chaos testing enabled: %v\\n\", chaosConfig.Enabled)\n\n// Configure chaos triggers\ntriggers := \u0026mailpit.ChaosTriggers{\n    AcceptConnections: 0.9,  // 90% success rate\n    RejectSenders:     0.1,  // 10% sender rejection\n    DelayConnections:  0.2,  // 20% connection delay\n    DelayDuration:     5,    // 5 second delays\n}\n\nupdated, err := client.SetChaosConfig(ctx, triggers)\nif err != nil {\n    log.Fatal(err)\n}\nfmt.Printf(\"Chaos triggers updated: %+v\\n\", updated)\n```\n\n### Error Handling\n\n```go\nmessage, err := client.GetMessage(ctx, \"invalid-id\")\nif err != nil {\n    var mailpitErr *mailpit.Error\n    if errors.As(err, \u0026mailpitErr) {\n        switch mailpitErr.Type {\n        case mailpit.ErrorTypeAPI:\n            if mailpitErr.StatusCode == 404 {\n                fmt.Println(\"Message not found\")\n            } else {\n                fmt.Printf(\"API error %d: %s\\n\", mailpitErr.StatusCode, mailpitErr.Message)\n            }\n        case mailpit.ErrorTypeNetwork:\n            fmt.Println(\"Network error:\", mailpitErr.Message)\n        case mailpit.ErrorTypeValidation:\n            fmt.Println(\"Validation error:\", mailpitErr.Message)\n        case mailpit.ErrorTypeTimeout:\n            fmt.Println(\"Request timed out:\", mailpitErr.Message)\n        }\n    } else {\n        fmt.Println(\"Unknown error:\", err)\n    }\n}\n```\n\n## 🧪 Testing Integration\n\nThis client is designed for seamless integration with [testcontainers](https://testcontainers.com/) for comprehensive testing:\n\n```go\nfunc TestWithMailpit(t *testing.T) {\n    ctx := context.Background()\n\n    // Start Mailpit container\n    container, err := testcontainers.GenericContainer(ctx,\n        testcontainers.GenericContainerRequest{\n            ContainerRequest: testcontainers.ContainerRequest{\n                Image:        \"axllent/mailpit:latest\",\n                ExposedPorts: []string{\"8025/tcp\", \"1025/tcp\"},\n                WaitingFor:   wait.ForHTTP(\"/api/v1/info\").WithPort(\"8025/tcp\"),\n                Env: map[string]string{\n                    \"MP_SMTP_AUTH_ACCEPT_ANY\": \"1\",\n                    \"MP_SMTP_AUTH_ALLOW_INSECURE\": \"1\",\n                },\n            },\n            Started: true,\n        })\n    require.NoError(t, err)\n    defer container.Terminate(ctx)\n\n    // Get container connection details\n    host, err := container.Host(ctx)\n    require.NoError(t, err)\n\n    httpPort, err := container.MappedPort(ctx, \"8025\")\n    require.NoError(t, err)\n\n    smtpPort, err := container.MappedPort(ctx, \"1025\")\n    require.NoError(t, err)\n\n    // Create API client\n    client, err := mailpit.NewClient(\u0026mailpit.Config{\n        BaseURL: fmt.Sprintf(\"http://%s:%s\", host, httpPort.Port()),\n        Timeout: 10 * time.Second,\n    })\n    require.NoError(t, err)\n    defer client.Close()\n\n    // Send test email via SMTP\n    smtpClient, err := smtp.Dial(fmt.Sprintf(\"%s:%s\", host, smtpPort.Port()))\n    require.NoError(t, err)\n    defer smtpClient.Close()\n\n    err = smtpClient.Mail(\"test@example.com\")\n    require.NoError(t, err)\n\n    err = smtpClient.Rcpt(\"recipient@example.com\")\n    require.NoError(t, err)\n\n    writer, err := smtpClient.Data()\n    require.NoError(t, err)\n\n    _, err = writer.Write([]byte(`Subject: Test Email\nFrom: test@example.com\nTo: recipient@example.com\n\nThis is a test email body.`))\n    require.NoError(t, err)\n    require.NoError(t, writer.Close())\n\n    // Wait for message processing\n    time.Sleep(2 * time.Second)\n\n    // Verify message received\n    messages, err := client.ListMessages(ctx, nil)\n    require.NoError(t, err)\n    require.Equal(t, 1, messages.Total)\n\n    message := messages.Messages[0]\n    assert.Equal(t, \"Test Email\", message.Subject)\n    assert.Equal(t, \"test@example.com\", message.From.Address)\n}\n```\n\n## 📊 API Coverage\n\nThis client provides **100% coverage** of the Mailpit API endpoints. For detailed endpoint mapping and implementation status, see our [API Coverage Documentation](API_COVERAGE.md).\n\n### Automated Coverage Testing\n\nWe maintain automated testing to ensure complete API coverage:\n\n```bash\n# Run full API coverage validation\nmake test-api-coverage\n\n# Run fast offline coverage test\nmake test-api-coverage-offline\n```\n\n## 🛠️ Development\n\n### Prerequisites\n\n- Go 1.25.0+\n- Docker (for testing)\n- Make\n- [golangci-lint](https://golangci-lint.run/) (for linting)\n\n### Development Commands\n\n```bash\n# Install dependencies\ngo mod download\n\n# Run tests\nmake test\n\n# Run linting\nmake check\n\n# Auto-fix lint issues\nmake fix\n\n# Run field alignment optimization\nmake fieldalign\n\n# Security scanning\nmake security\n\n# Generate TLS certificates for testing\nmake mkcert-generate HOSTS='localhost 127.0.0.1 ::1'\n```\n\n### Testing\n\nThe project includes comprehensive testing:\n\n- **Unit Tests**: Test individual functions and methods\n- **Integration Tests**: End-to-end testing with real Mailpit instances\n- **API Coverage Tests**: Automated verification of complete API coverage\n\n```bash\n# Run all tests\nmake test\n\n# Run with coverage\ngo test -race -coverprofile=coverage.out ./...\n\n# View coverage report\ngo tool cover -html=coverage.out\n```\n\n## 📚 Documentation\n\n- [API Coverage Documentation](API_COVERAGE.md) - Complete endpoint mapping\n- [GoDoc](https://pkg.go.dev/github.com/CodeLieutenant/mailpitclient) - Comprehensive API documentation\n- [Mailpit Documentation](https://mailpit.axllent.org/) - Official Mailpit documentation\n\n## 🤝 Contributing\n\nContributions are welcome! Please follow these guidelines:\n\n1. **Fork** the repository\n2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)\n3. **Commit** your changes (`git commit -m 'Add amazing feature'`)\n4. **Run** tests and linting (`make check test`)\n5. **Push** to the branch (`git push origin feature/amazing-feature`)\n6. **Open** a Pull Request\n\n### Code Standards\n\n- Follow the established patterns in the codebase\n- Add tests for new functionality (unit + E2E)\n- All tests must use `t.Parallel()` for parallel execution\n- Maintain \u003e90% code coverage\n- Use `make check` to validate code quality\n- Update documentation as needed\n\n## 📄 License\n\nThis project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.\n\n## 🔗 Related Projects\n\n- [Mailpit](https://github.com/axllent/mailpit) - The email testing tool this client connects to\n- [Testcontainers Go](https://github.com/testcontainers/testcontainers-go) - Docker testing framework used in our test suite\n\n## ⭐ Support\n\nIf you find this project helpful, please consider giving it a star on GitHub!\n\nFor bugs, feature requests, or questions, please [open an issue](https://github.com/CodeLieutenant/mailpitclient/issues).\n\n---\n\n*Built with ❤️ for the Go community*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodelieutenant%2Fmailpitclient","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodelieutenant%2Fmailpitclient","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodelieutenant%2Fmailpitclient/lists"}