{"id":35170701,"url":"https://github.com/goyal-aman/smtpmux","last_synced_at":"2026-01-13T22:45:44.175Z","repository":{"id":330837133,"uuid":"1124124002","full_name":"goyal-aman/smtpmux","owner":"goyal-aman","description":"SMTP Mux is a programmable SMTP proxy that multiplexes outbound email at runtime via plugins, allowing fine-grained control over delivery based on sender, recipient, domain, volume, health checks, or custom policies.","archived":false,"fork":false,"pushed_at":"2026-01-06T10:12:16.000Z","size":17384,"stargazers_count":27,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T22:45:41.518Z","etag":null,"topics":["devops-tools","email-sender","emails","go","golang","high-availability","mail-relay","mux","router","smtp","smtp-client","smtp-mail","smtp-server"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goyal-aman.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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-12-28T11:42:04.000Z","updated_at":"2026-01-13T16:48:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/goyal-aman/smtpmux","commit_stats":null,"previous_names":["goyal-aman/smtpmux"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/goyal-aman/smtpmux","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goyal-aman%2Fsmtpmux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goyal-aman%2Fsmtpmux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goyal-aman%2Fsmtpmux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goyal-aman%2Fsmtpmux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goyal-aman","download_url":"https://codeload.github.com/goyal-aman/smtpmux/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goyal-aman%2Fsmtpmux/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28405125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T21:51:37.118Z","status":"ssl_error","status_checked_at":"2026-01-13T21:45:14.585Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["devops-tools","email-sender","emails","go","golang","high-availability","mail-relay","mux","router","smtp","smtp-client","smtp-mail","smtp-server"],"created_at":"2025-12-28T20:39:05.190Z","updated_at":"2026-01-13T22:45:44.171Z","avatar_url":"https://github.com/goyal-aman.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SMTP Mux\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/Mindbaz/awesome-opensource-email/\"\u003e\n    \u003cimg src=\"smtpmux.svg\" alt=\"Awesome Opensource Email\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\n\nSmtpMux is a pluggable SMTP proxy and router written in Go that solves these reliability issues by acting as an intelligent intermediary (multiplexer) between your applications and your mail providers.\n\nMany self-hosted applications and microservices (such as Vaultwarden, Nextcloud, or Gitea) only support the configuration of a single SMTP server. This creates a critical single point of failure in the system's communication layer:\n\n* Service Downtime: If the primary mail provider (e.g., Gmail, Zoho, or SendGrid) experiences an outage, the application loses the ability to send password resets, 2FA codes, and urgent notifications.\n\n* Rate Limiting: Free or low-tier SMTP plans often have strict hourly or daily sending limits. Once reached, subsequent emails are blocked, which can break essential workflows.\n\n* Lack of Native Failover: Most applications do not have built-in logic to switch to a backup provider or distribute traffic intelligently, forcing users to manually reconfigure settings during an emergency.\n\n```mermaid\ngraph TD\n    %% Node Definitions\n    App1([User App A])\n    App2([User App B])\n    App3([Microservice C])\n\n    subgraph MUX_CORE [\"smtpmux Proxy Layer\"]\n        direction TB\n        Ingress{{\"📥 SMTP Ingress \u003cbr/\u003e (Port 25/587)\"}}\n        \n        subgraph ENGINE [\"Logic Engine\"]\n            direction LR\n            Auth[(\"Auth \u0026 TLS\u003cbr/\u003eTermination\")]\n            Parser{\"Parser \u0026\u003cbr/\u003eQueue\"}\n            Router{{\"🚦 Multiplexer\u003cbr/\u003eStrategy\"}}\n        end\n\n        StateDB[(State Memory)]\n    end\n\n    subgraph UPSTREAMS [\"Encrypted Upstream Tunnels\"]\n        P1[\"Gmail (Primary)\"]\n        P2[\"AWS SES (Secondary)\"]\n        P3[\"SendGrid (Tertiary)\"]\n    end\n\n    %% Connections\n    App1 \u0026 App2 \u0026 App3 ==\u003e|Plain/STARTTLS| Ingress\n    Ingress --\u003e Auth\n    Auth --\u003e Parser\n    Parser --\u003e Router\n    Router \u003c--\u003e|Check Health| StateDB\n\n    %% Routing Paths\n    Router -.-\u003e|1. Attempt| P1\n    Router -.-\u003e|2. Failover| P2\n    Router -.-\u003e|3. Fallback| P3\n\n    %% Styling\n    classDef app fill:#2d3436,stroke:#0984e3,stroke-width:2px,color:#fff;\n    classDef engine fill:#1e272e,stroke:#00d2d3,stroke-width:2px,color:#fff;\n    classDef gate fill:#2f3542,stroke:#ff9f43,stroke-width:3px,color:#fff;\n    classDef provider fill:#2d3436,stroke:#1dd1a1,stroke-width:2px,color:#fff;\n\n    class App1,App2,App3 app;\n    class Ingress,Auth,Parser engine;\n    class Router gate;\n    class P1,P2,P3 provider;\n    class StateDB engine;\n```\n\n## Quick Start\n\nFull the image from registry with local smtp downstreams\n```\ndocker pull ghcr.io/goyal-aman/smtpmux:latest\n```\n\nCreate config.yaml \n```\nusers:\n  - email: \"test@user.com\"\n    password: \"password123\"\n    selector_algo_path: \"./plugins/round_robin/round-robin-plugin\"\n    downstreams:\n      - addr: \"mailserve1:1025\"\n        user: \"any\"\n        pass: \"any\"\n      - addr: \"mailserve2:1025\"\n        user: \"any\"\n        pass: \"any\"\n```\n\nStart downstreams\n```\ndocker network create smtpmux-net\ndocker run --rm -d -p 8026:8025 --name mailserve1 --network=smtpmux-net mailhog/mailhog\ndocker run --rm -d -p 8027:8025 --name mailserve2 --network=smtpmux-net mailhog/mailhog\n```\n\nOpen localhost:8026 and localhost:8027 in brower to see the emails.\n\nStart smtpmux\n```\ndocker run -p 1024:1020 \\\n        -v $(pwd)/config.yaml:/app/config.yaml \\\n        --network=smtpmux-net \\\n        -e USE_INSECURE_AUTH=true \\\n        ghcr.io/goyal-aman/smtpmux:latest\n```\n\nsmptmux is now running. Now lets try to send an email through it. \n\nRun this few times so see round robin in action\n```\nswaks --to hello@smtpmux.what \\\n      --from curious@user.com \\\n      --server localhost:1024 \\\n      -a PLAIN \\\n      --auth-user test@user.com \\\n      --auth-password password123 \\\n      --body \"hello user\"\n```\n\n**Verify delivery:**\n    Open http://localhost:8026 and http://localhost:8027. You should see the email appear in one of them, depending on the routing logic.\n\n## Features\n- **Dynamic Routing**: Route emails based on sender, recipient, or custom logic.\n- **Plugin System**: Write routing logic in Go using the `go-plugin` architecture.\n- **Docker Ready**: Fully containerized for easy deployment.\n- **Protocol Support**: Supports standard SMTP authentication (PLAIN).\n\n## Custom Selector Algorithms\n\nYou can write your own routing logic in Go by implementing the `Selector` interface.\n\n1.  **Create a new plugin**:\n    Start from ./plugins/round_robin/main.go and modify the select logic as per your needs.\n    ```go\n    type MySelector struct{}\n\n    func (s *MySelector) Select(downstreams []types.Downstream) (string, error) {\n        // Your custom logic here\n        // e.g., return downstreams[0].Addr, nil\n    }\n    ```\n\n2.  **Build the plugin**:\n    ```bash\n    go build -o my-plugin ./my_plugin.go\n    ```\n\n3.  **Update Config**:\n    Point `config.yaml` to your new binary:\n    ```yaml\n    selector_algo_path: \"./my-plugin\"\n    ```\n\n4.  **Mount \u0026 Restart**:\n    If using Docker, mount the binary into the container and restart.\n\n## Docker\n\nRun with Docker:\n\n```bash\ndocker build -t smtp-router .\ndocker run -p 1020:1020 -v $(pwd)/config.yaml:/app/config.yaml -v $(pwd)/round_robin.star:/app/round_robin.star smtpmux\n```\n\n## Development\n\nRun tests:\n```bash\ngo test ./...\n```\n\n## Examples\n\n### Downstream 1 (Port 1026)\n```bash\ndocker run --rm -d -p 1027:1025 -p 8027:8025 --name mailserve1 mailhog/mailhog\n```\n\n### Downstream 2 (Port 1027)\n```bash\ndocker run --rm -d -p 1026:1025 -p 8026:8025 --name mailserve2 mailhog/mailhog\n```\n\n## Send Email Locally\n```\nswaks --to recipient@example.com \\\n      --from test@user.com \\\n      --server localhost:1022 \\\n      -a PLAIN \\\n      --auth-user test@user.com \\\n      --auth-password password123 \\\n      --body \"maaaa\"\n```\n\n## Dynamic Selector (Starlark)\nTODO: update for go plugins\nYou can define your own routing logic in a Starlark script (Python-like syntax).\n\nExample `round_robin.star`:\n\n```python\ndef selector(downstreams):\n    for ds in downstreams:\n        err = send(ds=ds)\n        if err == None:\n            return None\n    return \"all failed\"\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoyal-aman%2Fsmtpmux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoyal-aman%2Fsmtpmux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoyal-aman%2Fsmtpmux/lists"}