- Go 99.3%
- Dockerfile 0.7%
Tenants can forward submissions as JSON to a webhook instead of or in addition to SMTP. The webhook supports a bearer token, custom headers and a timeout. All configured channels are attempted; any failure redirects to the error page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| testdata | ||
| .dockerignore | ||
| .gitignore | ||
| altcha.go | ||
| altcha_test.go | ||
| config.docker.yaml | ||
| config.go | ||
| config.yaml.example | ||
| config_test.go | ||
| cors.go | ||
| cors_test.go | ||
| docker-compose.example.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| form.go | ||
| form_test.go | ||
| go.mod | ||
| go.sum | ||
| handler.go | ||
| handler_test.go | ||
| helpers_test.go | ||
| LICENSE | ||
| mailer.go | ||
| mailer_test.go | ||
| main.go | ||
| README.md | ||
| spam.go | ||
| spam_test.go | ||
| webhook.go | ||
| webhook_test.go | ||
Post2Mail
Send your contact forms via email
Warning: this project is pretty much vibe coded from an existing node project.
Intro
Contact forms on websites are the most common method for users to reach out to the owners. They're also super simple to implement... theoretically. Forwarding them through email is not as straight forward. You'll need some kind of server for this.
This is my attempt to build the simplest docker service possible to allow exactly that. Handle contact form submissions via POST and forward them via configurable SMTP credentials and/or a webhook.
Quick start:
- cp docker-compose.example.yml docker-compose.yml
- cp config.yaml.example config.yaml
- Edit config.yaml (SMTP hosts, tenants, redirects, spam settings)
- docker compose up -d --build
Webhooks
Instead of (or in addition to) SMTP, a tenant can forward submissions to a webhook. Add a webhook section to the tenant; at least one of smtp or webhook must be configured. When both are set, both are called and the submission only counts as successful if both succeed.
webhook:
url: https://hooks.example.test/contact
token: "${WEBHOOK_TOKEN}" # sent as "Authorization: Bearer <token>"
headers: # optional, e.g. for services expecting an API key header
X-Api-Key: "${WEBHOOK_API_KEY}"
timeout: 10s # optional, default 10s
The webhook receives a POST with Content-Type: application/json; any 2xx response counts as success:
{
"tenant": "alpha",
"subject": "New contact form submission",
"submitted_at": "2026-10-18T12:00:00Z",
"fields": { "name": "Alice", "message": "Hi!" },
"attachments": [
{ "filename": "cv.pdf", "content_type": "application/pdf", "size": 12345, "data": "<base64>" }
]
}
Using ALTCHAv2
To use ALTCHAv2, add the altcha section to your tenant config in config.yaml. See the example config for details.
You can specify your algorithm from the PBKDF2 algorithms. The other derivation algorithms are not supported.
On your frontend, it will look something similar to:
<form action="https://mail.example.test/forms/alpha" method="POST" enctype="multipart/form-data">
<!-- your fields -->
<altcha-widget challengeurl="https://mail.example.test/forms/alpha/altcha"></altcha-widget>
<button type="submit">Send</button>
</form>
<!--Or just load it through npm ®-->
<script async defer src="https://cdn.jsdelivr.net/npm/altcha/dist/altcha.min.js" type="module"></script>