Small surface area
One authenticated email endpoint, one health check, and no unnecessary runtime dependencies.
Self-hosted email infrastructure
egate is a focused application-to-application email gateway backed by SQLite and Postmark. Centralize provider credentials, issue revocable API keys, and send transactional email over a small HTTP API.
One authenticated email endpoint, one health check, and no unnecessary runtime dependencies.
Create separate keys for each application and revoke access without rotating your Postmark server token.
A single Go binary, a SQLite database, and a Docker workflow with persistent local storage.
Quickstart
Send a JSON request to your egate host with an API key in the bearer authorization header.
curl https://egate.example.com/v1/email \
-H 'Authorization: Bearer eg_YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{
"from": "sender@example.com",
"to": "recipient@example.com",
"subject": "Hello from egate",
"text_body": "Your transactional email is ready."
}'HTTP API
Submits a message to Postmark. egate passes the provider response body and HTTP status through unchanged.
AuthorizationrequiredBearer eg_YOUR_KEY
Content-Typerequiredapplication/json
fromstring · requiredSender address accepted by your Postmark account.
tostring · requiredRecipient address.
subjectstring · requiredMessage subject.
text_bodystringPlain-text body. At least one of text_body or html_body is required.
html_bodystringHTML message body.
reply_tostring · optionalAddress used for recipient replies.
2xxPostmark accepted the request. The exact provider status and JSON response are returned.
400The JSON is invalid or a required field is missing.
401The bearer token is missing, invalid, or revoked.
502The email provider could not be reached.
Go SDK
Install the module, construct a client with your deployment URL and API key, then send a typed message.
go get github.com/englandsystems/egateclient, err := sdk.NewClient(
"https://egate.example.com",
os.Getenv("EGATE_API_KEY"),
)
if err != nil {
log.Fatal(err)
}
response, err := client.SendEmail(ctx, sdk.Email{
From: "sender@example.com",
To: "recipient@example.com",
Subject: "Hello from egate",
TextBody: "Your transactional email is ready.",
})Operations
egate is designed to sit behind a TLS reverse proxy. Persist its SQLite data directory and keep credentials outside the image.
GET /healthzReturns {"ok":true} with status 200 when the process can serve traffic.
Request sizeEmail request bodies are limited to 1 MiB.
TimeoutsProvider requests time out after 15 seconds.
PersistenceAPI keys, sessions, and security records live in the configured SQLite database.
Transport securityTerminate TLS at a reverse proxy and restrict direct access to the application port in production.