Configuration
Courier's config file lives at app/Config/Courier.php after you publish it. Every option has a default that works out of the box — you only need to set what you want to change.
Options
$fromName / $fromEmail
The default sender name and address for all outgoing emails. Individual campaigns can override these — these values are the fallback when a campaign doesn't specify its own.
$defaultLayout
The email layout view used when a campaign doesn't have one set. Courier ships with a simple responsive layout at Views/courier/layouts/default.php. Point this at your own view to apply a custom look site-wide.
See Email Templates for how layouts work.
$trackingHost
The base URL used to build tracking pixel URLs, click redirect URLs, and unsubscribe links. Leave empty and Courier will use CI4's base_url() automatically. Set it if you're using a custom tracking domain:
$batchSize
How many emails to send per courier:send-campaign or courier:process-drips command run. If a campaign has 10,000 contacts, the command works through them in chunks of 200 across successive cron runs.
Lower this if you're hitting rate limits; raise it if your email provider supports higher throughput.
$retryDelayMinutes
How long to wait before retrying a drip step send that failed. When courier:process-drips can't deliver a step (the mailer returns false or throws), it pushes the enrollment's next_send_at forward by this many minutes instead of retrying immediately.
5 minutes is a sensible default — long enough to survive a brief ESP blip, short enough that recipients aren't delayed noticeably. For high-volume setups you may want a longer window to avoid hammering a struggling provider:
$maxRetries
Maximum number of send attempts per drip step before Courier gives up. After this many failures, the enrollment is marked failed and a courier_enrollment_failed event fires so your app can take action.
With the defaults (retryDelayMinutes = 5, maxRetries = 3), a step that keeps failing will be abandoned after roughly 15 minutes and 3 attempts. Raise this if you expect longer ESP outages:
$throttleMs
Milliseconds to sleep between individual sends within a batch. 0 means no delay. Set this if your email provider has a per-second sending limit:
$markdownPath
The base directory Courier uses when resolving markdown email files. Leave empty and it defaults to APPPATH (your app's app/ folder). Set an absolute path to load markdown files from a different location:
With this set, a campaign view of welcome.md resolves to app/Emails/welcome.md.
See Email Templates for the full markdown workflow.
$testMode
When true, Courier skips the actual mailer and logs what it would send instead. Use this in development or CI to verify your campaign setup without delivering real emails:
You'll see log entries like:
Environment-specific config
You can override any config value per-environment using CI4's .env file:
$captureRateLimit
Maximum number of POST submissions allowed per IP address per minute on the /courier/capture endpoint. Requests over the limit receive a 429 Too Many Requests response — a redirect back with a courier_errors flash message for standard form submissions, or a JSON error for AJAX requests.
Set to 0 to disable rate limiting entirely:
For high-traffic sites or shared hosting environments where many users may share an IP, you can raise the limit:
$honeypot
When true, Courier renders a hidden courier_hp field in forms generated by courier_form() and courier_form_open(). Real users never see or fill this field. Bots that blindly populate all inputs get silently rejected — Courier returns a success response without saving anything.
Set to false to opt out:
Custom form layouts
If you build your own form markup and post to /courier/capture, the honeypot check still runs server-side. To avoid false rejections, make sure your form doesn't submit a courier_hp field — or disable the honeypot if you can't control the submitted fields.
$trackIpAddress
When true, the IP address of the recipient who clicked a tracked link is stored in the metadata column of courier_events.
Default is false. IP addresses are personal data under GDPR and CCPA. Only enable this setting if:
- Your privacy policy discloses that click IP addresses are collected and processed, and
- You have a data-retention policy that covers
courier_eventsrows.
To enable:
$webhookDriver
The fully-qualified class name of a WebhookDriverInterface implementation that handles incoming ESP webhook notifications (bounces, complaints, subscription confirmations). Leave empty to disable the POST /courier/webhook endpoint — it returns 400 when no driver is configured.
Courier ships with a driver for AWS SES (routed through SNS):
To use a different ESP, implement WebhookDriverInterface and point this at your class.
CSRF exemption required
The webhook endpoint receives machine-to-machine POST requests from your ESP. You must add 'courier/webhook' to $CSRFExcludeURIs in app/Config/Security.php, otherwise all webhook calls will be rejected.
See Tracking — Bounce and complaint webhooks for the full setup walkthrough.