Skip to content

Repository files navigation

staticSend

A self-hosted, secure contact form processing service for static websites. Enable functional contact forms on your static sites without backend code, with built-in spam protection and email forwarding.

GoLicenseDocker

✨ Features

  • 🔒 Cloudflare Turnstile Integration - Bot protection with zero user friction
  • 🛡️ Authentication Bot Protection - Optional Turnstile protection for login/register pages
  • ⏱️ Rate Limiting - IP-based request limiting to prevent abuse
  • 📧 Email Forwarding - Send form submissions directly to your inbox
  • ↪️ Optional Callback Redirect - Redirect users to a custom URL after successful submission
  • 🖥️ Web Management UI - HTMX-based interface for easy form management
  • 🐳 Docker Ready - Easy deployment with containerization
  • 💾 SQLite Database - Simple, file-based persistence
  • 🔐 JWT Authentication - Secure admin access
  • 📱 Responsive Design - Mobile-friendly management interface

🚀 Quick Start

Prerequisites

  • Go 1.21+ (for development)
  • Docker (for production deployment)
  • Cloudflare Turnstile keys (get them here)
  • SMTP credentials (Gmail, SendGrid, etc.)

Docker Deployment

# Create a directory for persistent data
mkdir -p /opt/staticsend/data
# Run with Docker
docker run -d \
--name staticsend \
-p 8080:8080 \
-v /opt/staticsend/data:/data \
-e STATICSEND_PORT=8080 \
-e STATICSEND_JWT_SECRET=your-super-secret-jwt-key \
-e STATICSEND_SMTP_HOST=smtp.gmail.com \
-e STATICSEND_SMTP_PORT=587 \
-e STATICSEND_SMTP_USER=your-email@gmail.com \
-e STATICSEND_SMTP_PASS=your-app-password \
-e TURNSTILE_PUBLIC_KEY=your-turnstile-public-key \
-e TURNSTILE_SECRET_KEY=your-turnstile-secret-key \
ghcr.io/CaffeinatedTech/staticsend:latest

Manual Installation

# Clone the repository
git clone https://github.com/CaffeinatedTech/staticsend.git
cd staticsend
# Build the binary
go build -o staticsend .# Set environment variablesexport STATICSEND_PORT=8080
export STATICSEND_DB_PATH=./staticsend.db
export STATICSEND_JWT_SECRET=your-jwt-secret
export STATICSEND_SMTP_HOST=smtp.gmail.com
export STATICSEND_SMTP_PORT=587
export STATICSEND_SMTP_USER=your-email@gmail.com
export STATICSEND_SMTP_PASS=your-app-password
export TURNSTILE_PUBLIC_KEY=your-turnstile-public-key
export TURNSTILE_SECRET_KEY=your-turnstile-secret-key
# Run the application
./staticsend
# Or with custom port
./staticsend -port=3000

📋 Configuration

Command Line Flags

FlagDescriptionDefaultEnvironment Variable
-portHTTP server port8080STATICSEND_PORT

Environment Variables

Core Application

VariableDescriptionDefaultRequired
PORTHTTP server port8080No
DATABASE_PATHSQLite database path./data/staticsend.dbNo
JWT_SECRET_KEYJWT signing secret-Yes
REGISTRATION_ENABLEDEnable user registrationtrueNo
STATICSEND_BASE_URLBase URL for generating full submission URLs (e.g., https://staticsend.example.com)http://localhost:8080No

Email Configuration

VariableDescriptionDefaultRequired
EMAIL_HOSTSMTP server host-Yes
EMAIL_PORTSMTP server port587No
EMAIL_USERNAMESMTP username-Yes
EMAIL_PASSWORDSMTP password-Yes
EMAIL_FROMFrom email address-Yes
EMAIL_USE_TLSUse TLS for SMTPtrueNo

Turnstile Bot Protection

VariableDescriptionDefaultRequired
TURNSTILE_PUBLIC_KEYTurnstile public key for login/register pages-No
TURNSTILE_SECRET_KEYTurnstile secret key for login/register pages-No

S3 Backup Configuration (Optional)

VariableDescriptionDefaultRequired
S3_ENDPOINTS3-compatible storage endpoint-For backups
S3_BUCKETS3 bucket name-For backups
S3_ACCESS_KEYS3 access key-For backups
S3_SECRET_KEYS3 secret key-For backups
S3_REGIONS3 regionus-east-1No
CLEANUP_OLD_BACKUPSAuto-delete backups older than 30 daystrueNo

Cronivore Monitoring (Optional)

VariableDescriptionDefaultRequired
CRONIVORE_CHECK_SLUGCronivore check slug for backup monitoring-No
CRONIVORE_URLCronivore service URLhttps://cronivore.comNo

🛠️ Usage

1. Create a Contact Form

  1. Access the web UI at http://localhost:8080
  2. Register an account and log in
  3. Create a new contact form with:
    • Form name and domain
    • Cloudflare Turnstile keys (public and secret)
    • Destination email address
    • Optional Callback URL (redirect users here after a successful submission)

2. Integrate with Your Static Site

Add this HTML to your static website:

<formaction="https://your-staticsend-instance.com/api/v1/submit/YOUR_FORM_KEY" method="POST"><inputtype="text" name="name" placeholder="Your Name" required><inputtype="email" name="email" placeholder="Your Email" required><textareaname="message" placeholder="Your Message" required></textarea><!-- Cloudflare Turnstile --><divclass="cf-turnstile" data-sitekey="YOUR_TURNSTILE_PUBLIC_KEY"></div><buttontype="submit">Send Message</button></form><scriptsrc="https://challenges.cloudflare.com/turnstile/v0/api.js" asyncdefer></script>

3. Receive Submissions

Form submissions will be:

  1. Validated by Cloudflare Turnstile
  2. Rate-limited by IP address
  3. Forwarded to your specified email address
  4. Stored in the database for review

If you configured a Callback URL on the form, the submitter will be redirected to that URL with an HTTP 303 See Other after a successful submission. If no Callback URL is configured, the API responds with a JSON payload indicating success (HTTP 201 Created).

🔌 API Reference

Public Endpoints

Submit Form

POST /api/v1/submit/{form_key}Content-Type: application/x-www-form-urlencodedname=John&email=john@example.com&message=Hello&cf-turnstile-response=token

Response:

  • 201 Created with JSON body when no Callback URL is configured on the form:
{
"success": true,
"message": "Form submitted successfully",
"submission_id": 123
}
  • 303 See Other redirect to the configured Callback URL when present.

Management Endpoints (Require Authentication)

  • POST /api/auth/register - User registration
  • POST /api/auth/login - User login
  • GET /api/forms - List all forms
  • POST /api/forms - Create new form (fields: name, domain, turnstile_secret, forward_email, callback_url [optional])
  • GET /api/forms/{id} - Get form details
  • PUT /api/forms/{id} - Update form (fields: name, domain, turnstile_secret, forward_email, callback_url [optional])
  • DELETE /api/forms/{id} - Delete form
  • GET /api/submissions - List submissions (with optional form_id filter)

🧪 Development

Building from Source

# Clone the repository
git clone https://github.com/CaffeinatedTech/staticsend.git
cd staticsend
# Install dependencies
go mod download
# Build
go build -o staticsend .# Run tests
go test ./...
# Format code
go fmt ./...
# Run with hot reload (if using air)
air

Project Structure

staticsend/
├── cmd/staticsend/ # Main application entry point
├── pkg/ # Go packages
│ ├── api/ # HTTP handlers and routing
│ ├── auth/ # Authentication logic
│ ├── database/ # Database operations
│ ├── email/ # Email sending service
│ ├── middleware/ # HTTP middleware
│ ├── models/ # Data models
│ ├── turnstile/ # Cloudflare Turnstile integration
│ └── utils/ # Utility functions
├── templates/ # HTML templates for HTMX UI
├── migrations/ # Database migrations
└── internal/ # Private application code

📦 Deployment

Docker Compose

version: '3.8'services:
staticsend:
image: ghcr.io/CaffeinatedTech/staticsend:latestports:
- "8080:8080"volumes:
- staticsend_data:/app/dataenvironment:
- PORT=8080
- DATABASE_PATH=/app/data/staticsend.db
- JWT_SECRET_KEY=${JWT_SECRET}
- EMAIL_HOST=${EMAIL_HOST}
- EMAIL_PORT=${EMAIL_PORT}
- EMAIL_USERNAME=${EMAIL_USERNAME}
- EMAIL_PASSWORD=${EMAIL_PASSWORD}
- EMAIL_FROM=${EMAIL_FROM}
- TURNSTILE_PUBLIC_KEY=${TURNSTILE_PUBLIC_KEY}
- TURNSTILE_SECRET_KEY=${TURNSTILE_SECRET_KEY}restart: unless-stoppedvolumes:
staticsend_data:

Coolify Deployment

  1. Create a new service in Coolify using GitHub repository
  2. Select "Dockerfile" as build pack
  3. Configure environment variables (see Configuration section above)
  4. Add persistent volume: /app/data/var/lib/coolify/staticsend/data
  5. Deploy with health check on /health endpoint

For detailed Coolify setup instructions, see docs/deployment/coolify-setup.md

💾 Automated Backups

StaticSend includes an automated backup system that uploads database backups to S3-compatible storage.

Features

  • SQLite database backup using safe .backup command
  • S3-compatible storage (AWS S3, DigitalOcean Spaces, Backblaze B2, etc.)
  • Automatic compression and timestamping
  • Old backup cleanup (configurable retention period)
  • Cronivore monitoring integration for backup job monitoring
  • Coolify cron job integration

Quick Setup

  1. Configure S3 environment variables in Coolify:

    S3_ENDPOINT=https://s3.amazonaws.com
    S3_BUCKET=your-backup-bucket
    S3_ACCESS_KEY=your-access-key
    S3_SECRET_KEY=your-secret-key
  2. Create Coolify cron job:

    • Schedule: 0 2 * * * (daily at 2 AM)
    • Command: /app/backup.sh
  3. Optional Cronivore monitoring:

    CRONIVORE_CHECK_SLUG=your-check-slug

For complete backup setup instructions, see docs/deployment/backup-setup.md

🤝 Contributing

We welcome contributions! Please feel free to submit issues, feature requests, and pull requests.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Guidelines

  • Follow Go coding standards
  • Write tests for new functionality
  • Update documentation for changes
  • Use descriptive commit messages

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🆘 Support

🙏 Acknowledgments


staticSend - Making static websites more interactive, one form at a time. 🚀

About

A self-hosted form processing microservice for your static websites.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages