{"id":51413851,"url":"https://github.com/jfroy/etampe","last_synced_at":"2026-07-04T17:02:02.965Z","repository":{"id":358987597,"uuid":"1243995586","full_name":"jfroy/etampe","owner":"jfroy","description":"A small SMTP server bridge to Cloudflare Email Sending","archived":false,"fork":false,"pushed_at":"2026-06-04T23:43:39.000Z","size":80,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-05T01:11:57.468Z","etag":null,"topics":["cloudflare","email","smtp"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jfroy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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":"2026-05-19T21:40:10.000Z","updated_at":"2026-06-04T23:41:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jfroy/etampe","commit_stats":null,"previous_names":["jfroy/etampe"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jfroy/etampe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfroy%2Fetampe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfroy%2Fetampe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfroy%2Fetampe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfroy%2Fetampe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jfroy","download_url":"https://codeload.github.com/jfroy/etampe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfroy%2Fetampe/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35129190,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"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":["cloudflare","email","smtp"],"created_at":"2026-07-04T17:02:02.280Z","updated_at":"2026-07-04T17:02:02.952Z","avatar_url":"https://github.com/jfroy.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 💌 Étampe\n\n`etampe` is a small SMTP-to-Cloudflare Email Sending bridge for homelab Kubernetes clusters. It accepts SMTP on port `2525`, parses the message into Cloudflare's REST payload, sends through the Cloudflare Email Sending API, exposes `/healthz`, `/readyz`, and `/metrics` on port `8080`, and can export OpenTelemetry traces and metrics over OTLP.\n\n## Configuration\n\nPrerequisites:\n\n- A domain onboarded to [Cloudflare Email Service](https://developers.cloudflare.com/email-service/get-started/send-emails/) (SPF, DKIM, and bounce MX records configured).\n- A Cloudflare API token with the **Account / Email Service: Edit** permission scoped to the target account.\n\nRequired:\n\n- `CLOUDFLARE_ACCOUNT_ID`\n- `CLOUDFLARE_API_TOKEN`: API token with **Account / Email Service: Edit** permission.\n\nCommon options:\n\n- `CLOUDFLARE_FROM`: optional sender override for verified Cloudflare senders.\n- `SMTP_USERNAME` and `SMTP_PASSWORD`: enable SMTP AUTH PLAIN when both are set.\n- `SMTP_ALLOW_INSECURE_AUTH`: default `true` for private cluster networks; use TLS or NetworkPolicy when SMTP auth is enabled.\n- `SMTP_ADDR`: default `:2525`.\n- `HTTP_ADDR`: default `:8080`.\n- `OTEL_EXPORTER_OTLP_ENDPOINT`: enables OTLP trace and metric export.\n\nNotes:\n\n- Cloudflare `429` and `5xx` responses are returned to SMTP clients as temporary `451` failures; sender queues should retry.\n- Prometheus and OTLP metrics are both emitted. Avoid ingesting both into the same backend unless you de-duplicate.\n- SMTP certificates are loaded at startup; restart the pod after Kubernetes secret rotation.\n- SMTP `RCPT TO` is authoritative. `To:` and `Cc:` recipients not present in the envelope are stripped from the outbound Cloudflare payload, envelope recipients missing from visible headers are sent as `bcc`, and if no visible recipient remains the first envelope recipient is promoted to `to`.\n\n## Run\n\n```sh\ndocker run --rm -p 2525:2525 -p 8080:8080 \\\n  -e CLOUDFLARE_ACCOUNT_ID=... \\\n  -e CLOUDFLARE_API_TOKEN=... \\\n  ghcr.io/jfroy/etampe:latest\n```\n\n## Kubernetes\n\nCreate a secret:\n\n```sh\nkubectl create secret generic etampe \\\n  --from-literal=CLOUDFLARE_ACCOUNT_ID=... \\\n  --from-literal=CLOUDFLARE_API_TOKEN=...\n```\n\nApply a private `ClusterIP` deployment:\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: etampe\nspec:\n  selector:\n    matchLabels:\n      app: etampe\n  template:\n    metadata:\n      labels:\n        app: etampe\n    spec:\n      securityContext:\n        runAsNonRoot: true\n        seccompProfile:\n          type: RuntimeDefault\n      containers:\n        - name: etampe\n          image: ghcr.io/jfroy/etampe:latest\n          envFrom:\n            - secretRef:\n                name: etampe\n          ports:\n            - name: smtp\n              containerPort: 2525\n            - name: http\n              containerPort: 8080\n          readinessProbe:\n            httpGet:\n              path: /readyz\n              port: http\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: http\n          resources:\n            requests:\n              cpu: 10m\n              memory: 32Mi\n            limits:\n              memory: 128Mi\n          securityContext:\n            allowPrivilegeEscalation: false\n            capabilities:\n              drop: [\"ALL\"]\n            readOnlyRootFilesystem: true\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: etampe\nspec:\n  selector:\n    app: etampe\n  ports:\n    - name: smtp\n      port: 2525\n      targetPort: smtp\n    - name: http\n      port: 8080\n      targetPort: http\n```\n\nPoint in-cluster apps at `etampe.default.svc.cluster.local:2525`. Scrape `http://etampe:8080/metrics`.\n\n## See also\n\n- https://github.com/imrasalghul/mailbridge\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfroy%2Fetampe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjfroy%2Fetampe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfroy%2Fetampe/lists"}