Skip to content

Configuration Reference

Copilot edited this page Jul 11, 2026 · 1 revision

Configuration Reference

All runtime configuration is a template.yaml parameter, passed via --parameter-overrides on deploy - there is no separate config file to keep in sync with the CloudFormation stack.

Parameter Default Purpose
ProjectName nmailx Prefixes every resource name - see Renaming / white-labeling
JwtSigningSecret (required) Signs admin session JWTs
TurnstileSecretKey (required) Verifies Turnstile tokens on /send
LogRetentionDays 30 CloudWatch Logs retention for both Lambdas
SendLogRetentionDays 90 How long send-log entries live before TTL expiry
RateLimitBucketRetentionHours 48 How long rate-limit counter buckets live before TTL expiry
GlobalDailyCap 1000 Hard ceiling on sends/day across all domains
CustomDomainName (empty, optional) Custom hostname for /send and /admin - see Custom Domain Setup
CustomDomainCertificateArn (empty, optional) ACM certificate ARN for CustomDomainName, from the bootstrap/custom-domain.yaml stack

Per-domain rate limits (hourly/daily) are set per-domain in the dashboard (Domains -> Edit domain), not here - the parameters above are global ceilings and infrastructure knobs.

Notes per parameter

  • ProjectName flows into every resource name via !Sub in template.yaml, plus the dashboard's cookie name, JWT issuer, and page titles via the single APP_NAME constant in layers/common/python/nmailx_common/config.py. It's the only place the deployment's name lives - don't hardcode "nmailx" as a resource name literal anywhere else.
  • JwtSigningSecret / TurnstileSecretKey are NoEcho CloudFormation parameters, which land in Lambda environment variables. They're visible in plaintext to anyone with lambda:GetFunctionConfiguration in the AWS account, and rotation means a redeploy with new parameter values, not managed rotation. This is a deliberate tradeoff for a single-owner account - see the Security notes in the README, and don't "fix" it by introducing Secrets Manager or SSM Parameter Store (outside this project's pre-approved AWS service list).
  • LogRetentionDays / SendLogRetentionDays / RateLimitBucketRetentionHours all control TTL-style expiry - lowering them reduces DynamoDB/CloudWatch storage costs over time but shortens how far back you can look in the dashboard's Logs view or CloudWatch.
  • GlobalDailyCap is a hard ceiling across all domains combined - it exists as a last-resort circuit breaker independent of any single domain's per-domain rate limit, so a single misbehaving domain (or a bug) can't run up an unbounded SES bill.
  • CustomDomainName / CustomDomainCertificateArn default to empty, which leaves default behavior completely unchanged - the custom domain resources in template.yaml are only created when both are set. See Custom Domain Setup for the full walkthrough.

Renaming / white-labeling

nmailx is a placeholder name - nothing in the code depends on the literal string. To rebrand:

  1. Change the ProjectName parameter (drives every AWS resource name via !Sub in template.yaml) and redeploy with a matching --stack-name.
  2. That's it for functionality - ProjectName also flows into the dashboard's cookie name, JWT issuer, and page titles via APP_NAME.

The Python package name (nmailx_common) and the repo's folder name are cosmetic only - nothing reads them at runtime. Renaming them is a pure optional find-replace, not required.

Roles

Role Can do
Owner Everything: domains, users, templates, settings, logs
Editor Manage templates. Domains and logs are read-only. No user management
Viewer Read-only everywhere

Roles are set per-user (Users -> Add/Edit user) and enforced in src/admin_api/deps.py's require_roles() decorator on every route handler.

Clone this wiki locally