- Add contact form dialog with HTMX integration (hx-post) - Implement browser-only access middleware (blocks curl/Postman/wget) - Add rate limiting (5 requests/hour per IP) for contact endpoint - Implement honeypot and timing-based bot detection - Add input validation (email format, message length 10-5000 chars) - Create contact button in desktop and mobile navigation (last position) Security features: - Browser-only middleware validates User-Agent, Referer/Origin, HX-Request headers - Honeypot field returns fake success to fool bots while logging spam - Timing validation rejects forms submitted < 2 seconds - All security events logged for monitoring Documentation: - docs/SECURITY.md - Comprehensive security documentation - docs/HACK-CHALLENGE.md - "Try to Hack Me!" challenge for security researchers - docs/SECURITY-AUDIT-REPORT.md - Full security audit report - docs/CONTACT-FORM-QUICKSTART.md - Integration guide Form fields: email (required), name, company, subject, message (required)
13 KiB
Contact Form Email Backend - Implementation Guide
Overview
Complete backend implementation for a contact form with email delivery using SMTP (Gmail), featuring comprehensive security measures including CSRF protection, rate limiting, bot protection, and browser-only access.
Features Implemented
1. Email Service (internal/services/email.go)
- ✅ SMTP-based email sending with TLS support
- ✅ Gmail App Password authentication
- ✅ Email validation and sanitization
- ✅ Header injection prevention
- ✅ Configurable via environment variables
- ✅ Comprehensive error handling and logging
- ✅ Template-based email formatting
2. Contact Handler (internal/handlers/contact.go)
- ✅ POST endpoint:
/api/contact - ✅ Form field validation (email, name, company, subject, message)
- ✅ Bot protection with honeypot field
- ✅ Timing check (rejects forms submitted < 2 seconds)
- ✅ HTMX-friendly responses
- ✅ Detailed logging (without sensitive data)
3. Security Middleware
Contact Rate Limiting (internal/middleware/contact_rate_limit.go)
- ✅ 5 requests per hour per IP address
- ✅ Automatic cleanup of expired entries
- ✅ HTMX-friendly error responses
- ✅ Configurable limits and windows
CSRF Protection (internal/middleware/csrf.go)
- ✅ Token generation and validation
- ✅ 24-hour token TTL
- ✅ Cookie-based token storage
- ✅ Automatic token cleanup
- ✅ Support for forms and AJAX requests
Browser-Only Access (internal/middleware/browser_only.go)
- ✅ Blocks curl, Postman, wget, and other HTTP clients
- ✅ User-Agent validation
- ✅ Referer/Origin header validation
- ✅ Custom header requirement (HTMX or X-Browser-Request)
- ✅ Comprehensive bot detection
4. Configuration (internal/config/config.go)
- ✅ Email settings added to config struct
- ✅ Environment variable support
- ✅ Sensible defaults for development
5. HTMX Response Templates
- ✅
templates/partials/contact_success.html- Success message with animation - ✅
templates/partials/contact_error.html- Error message with shake animation
6. Route Registration (internal/routes/routes.go)
- ✅ Endpoint registered with full middleware chain
- ✅ Proper middleware ordering
Security Features
Multi-Layer Protection
Request → Browser-Only → Contact Rate Limit → CSRF → Handler
-
Browser-Only Middleware
- Blocks non-browser clients (curl, Postman, etc.)
- Validates User-Agent, Referer, and custom headers
-
Contact Rate Limiting
- 5 submissions per hour per IP
- Prevents spam and abuse
-
CSRF Protection
- Validates security tokens
- Prevents cross-site request forgery
-
Bot Protection in Handler
- Honeypot field detection
- Timing validation (min 2 seconds)
-
Input Validation
- Email format validation
- Length restrictions
- Header injection prevention
- XSS protection via sanitization
Environment Configuration
Required Variables
# SMTP Configuration (Gmail)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_FROM_EMAIL=your-email@gmail.com
CONTACT_EMAIL=txeo.msx@gmail.com
Gmail App Password Setup
- Enable 2FA in your Google account
- Visit: https://myaccount.google.com/apppasswords
- Generate an App Password for "Mail"
- Use the generated password in
SMTP_PASSWORD
Important: Never use your regular Gmail password - always use an App Password.
API Endpoint
POST /api/contact
Request Format:
POST /api/contact
Content-Type: application/x-www-form-urlencoded
HX-Request: true
Referer: http://yourdomain.com/
email=user@example.com
&name=John Doe
&company=Acme Inc
&subject=Partnership Inquiry
&message=Hello, I would like to discuss...
&website=
&submit_time=1701360000000
&csrf_token=abc123...
Required Fields:
email- Valid email address (max 254 chars)message- Message text (10-5000 chars)
Optional Fields:
name- Sender name (max 100 chars)company- Company name (max 100 chars)subject- Email subject (max 200 chars)
Special Fields:
website- Honeypot (must be empty)submit_time- Unix timestamp in millisecondscsrf_token- CSRF token from cookie
Success Response (200):
<div class="alert alert-success">
<h3>Message Sent Successfully!</h3>
<p>Thank you for reaching out...</p>
</div>
Error Responses:
- 403 Forbidden - Non-browser client, CSRF failure, or rate limit
- 400 Bad Request - Validation error
- 429 Too Many Requests - Rate limit exceeded
Testing
Test 1: Curl Request (Should Fail - 403)
curl -X POST http://localhost:1999/api/contact \
-d "email=test@example.com&message=Test" \
-w "\nStatus: %{http_code}\n"
Expected: Forbidden: Browser access only (403)
Test 2: Postman Request (Should Fail - 403)
curl -X POST http://localhost:1999/api/contact \
-H "User-Agent: PostmanRuntime/7.32.0" \
-H "Referer: http://localhost:1999/" \
-d "email=test@example.com&message=Test" \
-w "\nStatus: %{http_code}\n"
Expected: Forbidden: Browser access only (403)
Test 3: Browser-like Request (Should Fail - CSRF)
curl -X POST http://localhost:1999/api/contact \
-H "User-Agent: Mozilla/5.0 (Macintosh)" \
-H "Referer: http://localhost:1999/" \
-H "HX-Request: true" \
-d "email=test@example.com&message=Test" \
-w "\nStatus: %{http_code}\n"
Expected: CSRF validation error (403)
Test 4: Complete Browser Request
Use the test HTML file: test_contact_form.html
# Start server
go run main.go
# Open in browser
open http://localhost:1999/test_contact_form.html
# Fill and submit form
# Should succeed if SMTP credentials are configured
Integration Example
HTML Contact Form
<form
hx-post="/api/contact"
hx-target="#response"
hx-headers='{"X-Browser-Request": "true"}'
hx-on::before-request="this.submitTime.value = Date.now()"
>
<input type="hidden" name="submit_time" class="submitTime">
<input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
<!-- Honeypot -->
<div style="position: absolute; left: -9999px;">
<input type="text" name="website" tabindex="-1">
</div>
<input type="email" name="email" required>
<input type="text" name="name">
<input type="text" name="company">
<input type="text" name="subject">
<textarea name="message" required></textarea>
<button type="submit">Send</button>
</form>
<div id="response"></div>
<script>
// Initialize submit time
document.querySelector('.submitTime').value = Date.now();
</script>
JavaScript (Fetch API)
// Get CSRF token from cookie
const csrfToken = document.cookie
.split('; ')
.find(row => row.startsWith('csrf_token='))
?.split('=')[1];
const submitTime = Date.now();
// Wait at least 2 seconds before allowing submit
setTimeout(() => {
fetch('/api/contact', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Browser-Request': 'true'
},
body: new URLSearchParams({
email: 'user@example.com',
name: 'John Doe',
message: 'Hello!',
website: '', // Honeypot
submit_time: submitTime,
csrf_token: csrfToken
})
})
.then(response => response.text())
.then(html => {
document.getElementById('response').innerHTML = html;
});
}, 2000);
Email Template
The email sent to CONTACT_EMAIL follows this format:
Subject: [CV Contact] {subject or "New Message"}
New contact form submission:
From: user@example.com
Name: John Doe
Company: Acme Inc
Subject: Partnership Inquiry
Message:
Hello, I would like to discuss a potential partnership...
---
IP: 192.168.1.1
Time: 2025-11-30 13:45:22 UTC
Monitoring & Logging
Security Events Logged
-
Blocked Requests
- Non-browser User-Agents
- Missing Referer/Origin
- Missing browser headers
- CSRF validation failures
- Rate limit exceeded
- Honeypot triggered
- Form submitted too fast
-
Successful Submissions
- Email sent successfully (logs email address and IP)
-
Errors
- SMTP connection failures
- Email sending errors
- Template rendering errors
Log Format
2025/11/30 13:45:22 SECURITY: Blocked non-browser User-Agent from IP 192.168.1.1: curl/7.88.1
2025/11/30 13:45:23 SECURITY: CSRF validation failed from IP 192.168.1.2
2025/11/30 13:45:24 Contact form submitted successfully from user@example.com (192.168.1.3)
Production Deployment
Checklist
- Configure SMTP credentials in environment
- Set
CONTACT_EMAILto your email address - Enable HTTPS (middleware automatically enables HSTS)
- Configure
ALLOWED_ORIGINSif using custom domain - Set up log monitoring
- Test email delivery
- Monitor rate limit statistics
- Set up email delivery monitoring
- Configure email bounce handling
- Review security headers
Production Environment
# Production .env
GO_ENV=production
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
CONTACT_EMAIL=your-email@gmail.com
ALLOWED_ORIGINS=yourdomain.com,www.yourdomain.com
Troubleshooting
Email Not Sending
-
Check SMTP credentials
- Verify App Password is correct
- Ensure 2FA is enabled on Google account
-
Check logs
- Look for SMTP connection errors
- Verify email service initialization
-
Test SMTP connection
telnet smtp.gmail.com 587
Rate Limiting Issues
-
IP address detection
- Check
X-Forwarded-Forheader if behind proxy - Verify IP extraction in logs
- Check
-
Adjust limits
- Modify
limitandwindowincontact_rate_limit.go - Default: 5 requests per hour
- Modify
CSRF Token Issues
-
Token not set
- Ensure cookie is being set on GET requests
- Check browser cookie settings
-
Token mismatch
- Verify token is passed in form or header
- Check token expiration (24 hours)
Files Modified/Created
New Files
internal/services/email.go- Email service with SMTPinternal/handlers/contact.go- Contact form handlerinternal/middleware/contact_rate_limit.go- Rate limitinginternal/middleware/csrf.go- CSRF protectioninternal/middleware/browser_only.go- Browser validationtemplates/partials/contact_success.html- Success templatetemplates/partials/contact_error.html- Error templatetest_contact_form.html- Test page
Modified Files
internal/config/config.go- Added email configurationinternal/routes/routes.go- Registered contact endpointmain.go- Initialized contact handler and email service.env.example- Added email configuration example
Security Considerations
What's Protected Against
✅ CSRF Attacks - Token validation ✅ Rate Limiting Bypass - IP-based limiting ✅ Bot Submissions - Honeypot + timing + User-Agent ✅ Email Header Injection - Newline filtering ✅ XSS - Input sanitization ✅ External API Access - Browser-only enforcement ✅ Spam - Rate limiting + bot protection ✅ Brute Force - Rate limiting
What's NOT Protected Against
⚠️ Distributed Attacks - Single-IP rate limiting only ⚠️ Sophisticated Bots - May bypass basic User-Agent checks ⚠️ Email Bombing - Recipient rate limiting not implemented
Recommended Additions for Production
- CAPTCHA - Add reCAPTCHA or hCaptcha
- Email Verification - Verify sender's email address
- Advanced Bot Detection - Integrate with services like Cloudflare
- Distributed Rate Limiting - Use Redis for multi-server deployments
- Email Queue - Use background job processor for email sending
- Delivery Monitoring - Track email delivery success/failure
- Spam Detection - Content-based spam filtering
License & Reusability
This implementation is designed to be reusable across projects. Feel free to:
- Copy the entire
services/email.gofor email functionality - Reuse middleware components independently
- Adapt the contact handler for your needs
- Modify rate limits and validation rules
All code follows Go best practices and is production-ready.
Support
For issues or questions:
- Check the logs for detailed error messages
- Review security event logs for blocked requests
- Test with the included
test_contact_form.html - Verify SMTP credentials are correct
Implementation Date: November 30, 2025 Version: 1.0.0 Author: Backend Craftsman