Web interface for managing Sendry email servers.
- Template management with versioning and deployment
- Recipient list management with CSV/JSON import
- Campaign management with A/B testing support
- Send job management with pause/resume/cancel
- Multi-server support with load balancing strategies
- Server monitoring (queue, DLQ, domains, sandbox)
- OIDC authentication (Authentik, Keycloak, etc.)
Sendry Web is included in the sendry package. After installation:
# Start the service
sudo systemctl enable sendry-web
sudo systemctl start sendry-webConfiguration file: /etc/sendry/web.yaml
server:
listen_addr: ":8088"
tls:
enabled: false
cert_file: "/etc/sendry/certs/web.crt"
key_file: "/etc/sendry/certs/web.key"
database:
path: "/var/lib/sendry-web/app.db"
logging:
level: info # debug, info, warn, error
format: json # json, textSendry Web supports two authentication methods:
auth:
local_enabled: true
session_secret: "your-secret-key-at-least-32-chars"
session_ttl: 24hCreate local users via CLI:
sendry-web user create --email admin@example.com --password secretpasswordauth:
local_enabled: false # can be true for fallback
session_secret: "your-secret-key-at-least-32-chars"
session_ttl: 24h
oidc:
enabled: true
provider: "Authentik" # display name on login page
client_id: "sendry-web"
client_secret: "your-client-secret"
issuer_url: "https://auth.example.com/application/o/sendry-web/"
redirect_url: "https://panel.example.com/auth/callback"
scopes:
- openid
- profile
- email
allowed_groups: # optional, empty = allow all authenticated users
- "sendry-admins"Configure connections to Sendry MTA servers:
sendry:
servers:
- name: "mta-prod-1"
base_url: "https://mta-1.example.com"
api_key: "your-api-key"
env: "prod"
- name: "mta-stage"
base_url: "https://mta-stage.example.com"
api_key: "your-api-key"
env: "stage"
multi_send:
strategy: weighted_round_robin # round_robin, weighted_round_robin, domain_affinity
weights:
mta-prod-1: 3
mta-stage: 1
domain_affinity:
"example.com": "mta-prod-1"
failover:
enabled: true
max_retries: 2# Start server
sendry-web serve -c /etc/sendry/web.yaml
# Validate configuration
sendry-web config validate -c /etc/sendry/web.yaml# Create user
sendry-web user create --email admin@example.com --password secret
# List users
sendry-web user list
# Delete user
sendry-web user delete admin@example.com
# Reset password
sendry-web user reset-password admin@example.com# Run migrations
sendry-web migrate
# Cleanup old data
sendry-web cleanup --days 30 # clean job items older than 30 days
sendry-web cleanup --days 90 --dry-run # preview what would be deleted- Create and edit email templates with HTML editor
- Version history with diff comparison
- Deploy templates to Sendry servers
- Preview with variable substitution
- Create recipient lists
- Import from CSV or JSON
- Export to CSV
- Per-recipient variables for personalization
- Status tracking (active, unsubscribed, bounced)
- Create campaigns with sender settings
- Campaign-level variables
- A/B testing with multiple variants
- Weight-based traffic distribution
- Create send jobs from campaigns
- Schedule for future delivery
- Dry-run mode (test on first N recipients before full send)
- Real-time progress monitoring
- Pause, resume, cancel operations
- Retry failed items
- Dashboard with server status overview
- Queue and DLQ management
- Domain configuration view
- Sandbox message inspection
Templates support dynamic variable substitution using the {{variable_name}} syntax.
Variables are merged at send time with the following priority (highest to lowest):
- Recipient variables — individual data for each recipient from the list
- Campaign variables — shared values for all recipients in a campaign
- Global variables — server-wide defaults configured in Settings
If the same variable is defined at multiple levels, the higher priority value is used.
The following variables are automatically available:
| Variable | Description |
|---|---|
{{email}} |
Recipient's email address |
{{name}} |
Recipient's name (if specified in the list) |
When editing a template, the Variables (JSON) field serves two purposes:
- Documentation — describes what variables the template expects
- Test values — used when sending test emails via "Test Email" button
Example:
{
"company_name": "Acme Corp",
"unsubscribe_link": "https://example.com/unsubscribe",
"promo_code": "SUMMER2024",
"order_id": "12345"
}This field does not affect production email sending — it's for documentation and testing only.
Template HTML:
<p>Hello, {{name}}!</p>
<p>Your order #{{order_id}} has been shipped.</p>
<p>Use promo code <b>{{promo_code}}</b> for your next purchase.</p>
<p>Contact us at {{support_email}}</p>
<p><a href="{{unsubscribe_link}}">Unsubscribe</a></p>Configure global variables in Settings → Global Variables. These are available in all templates and can be overridden by campaign or recipient variables.
Common use cases:
- Company name and contact info
- Support email addresses
- Social media links
- Unsubscribe URLs
- Legal disclaimers
Special global variable used by Domains → Recommended DNS Records and by the dns-sync command.
- Key:
spf_include - Value: SPF domain of your upstream provider without
include:orv=spf1, for example_spf.mailgun.orgorspf.sendgrid.net.
When set, the recommended SPF value becomes v=spf1 a mx include:<value> ~all. When not set, it falls back to v=spf1 a mx ~all.
Sendry Web can compare a domain's current DNS records with the recommended SPF, DKIM and DMARC values and, if needed, create or update them through a DNS provider.
Supported providers: Cloudflare (API Token or legacy Global API Key), Namedot.
# Plan only (API Token)
sendry-web dns-sync --config /etc/sendry/web.yaml \
--domain example.com \
--token "$CLOUDFLARE_API_TOKEN"
# Apply changes (API Token)
sendry-web dns-sync --config /etc/sendry/web.yaml \
--domain example.com --apply \
--token "$CLOUDFLARE_API_TOKEN"
# Apply changes with legacy Global API Key
sendry-web dns-sync --config /etc/sendry/web.yaml \
--domain example.com --apply \
--email "$CLOUDFLARE_API_EMAIL" \
--token "$CLOUDFLARE_API_KEY"See the full DNS Sync guide for flags, output format, and authentication options.
- Session-based authentication with configurable TTL
- CSRF protection for state parameter in OIDC flow
- Secure cookie settings (HttpOnly, Secure, SameSite)
- Group-based access control with OIDC
- API key encryption in database (planned)
- Verify
issuer_urlis accessible from server - Check
redirect_urlmatches OIDC provider configuration - Ensure
client_idandclient_secretare correct - Check logs for detailed error messages
# Check database file permissions
ls -la /var/lib/sendry-web/app.db
# Run migrations manually
sendry-web migrate -c /etc/sendry/web.yaml- Verify
base_urlis accessible - Check API key is valid
- Ensure TLS certificates are trusted