A tiny CGI form mailer: receive form submissions over HTTP and deliver via SMTP.
Modern but dependency‑free: JSON POST, CORS allow‑list, honeypot, minimum fill time, and per‑IP rate limiting.
Designed to work on simple shared hosting with CGI enabled.
- JSON API (
application/json) with strict content handling and request size limit - CORS with explicit allow‑list (origins in env file)
- Honeypot field, minimum fill time, simple per‑IP rate limit (file‑based)
- Safe mail headers:
From= your mailbox (passes SPF/DKIM/DMARC),Reply-To= visitor - TLS via STARTTLS (587) or SMTPS (465)
- No external Python packages
- Upload
cgi-bin/contact.pyand make it executable:chmod 755 cgi-bin/contact.py
- Copy
cgi-bin/contact.env.exampletocgi-bin/contact.env, set your values, and protect it:chmod 600 cgi-bin/contact.env
- Place
cgi-bin/.htaccessnext tocontact.py(enables CGI and denies access tocontact.env). - Add a rewrite rule in your web root to map
/contactto the CGI. Useexamples/webroot.htaccessas a template. - Ensure your API subdomain (e.g.,
api.example.com) has TLS enabled. - Test from your machine:
curl -i -X OPTIONS https://api.example.com/contact -H 'Origin: https://www.example.com' -H 'Access-Control-Request-Method: POST' -H 'Access-Control-Request-Headers: Content-Type' curl -i -X POST https://api.example.com/contact -H 'Origin: https://www.example.com' -H 'Content-Type: application/json' --data '{"name":"Test","email":"test@example.org","subject":"Hello","message":"Ping","_elapsed_ms":"6000"}'
# SMTP
SMTP_HOST=mail.example.com
SMTP_TLS_MODE=starttls # starttls | ssl
SMTP_PORT=587 # 465 when SMTP_TLS_MODE=ssl
SMTP_USER=hello@example.com
SMTP_PASS=please-change-me
TO_ADDR=hello@example.com
# CORS
ALLOWED_ORIGINS=https://example.com,https://www.example.com
# Guards
MIN_ELAPSED_MS=5000 # minimum time user spent on the form (client also sends _elapsed_ms)
MIN_INTERVAL_S=30 # per-IP cooldown, file-based
# DoS guard
MAX_BODY=65536 # request body size limit in bytesSee exaples/contact-form.html and examples/assets/js/contact.js for a minimal integration.
Use your URL as the destination address for the form: hx-post="https://api.example.com/contact"
- The script strictly requires
application/jsonand rejects oversized bodies. - Header sanitization prevents header injection.
contact.envmust not be world‑readable and is denied in.htaccess.- Configure SPF, DKIM and DMARC for your domain; keep
From= your domain mailbox. - Rate limiting is basic and file‑based; add a WAF/Reverse‑Proxy limit if you need more.
MIT — see LICENSE.