Corndog for Craft CMS

Configuration

Settings live at Settings → Plugins → Corndog, and every one of them can be set in config/corndog.php instead — which is how you give staging different behaviour from production without touching the database.

<?php

return [
    'enabled' => true,

    // What to keep
    'storeHtmlBody' => true,
    'storeTextBody' => true,
    'storeHeaders' => true,
    'storeAttachmentDetails' => true,
    'maxBodySize' => 512,          // KB
    'storeIpAddresses' => true,
    'anonymiseIpAddresses' => true,

    // How long to keep it
    'retentionDays' => 60,         // 0 keeps everything
    'maxRows' => 5000,             // 0 for no cap

    // Tracking
    'trackOpens' => false,
    'trackClicks' => false,
    'ignoredLinkPatterns' => ['*unsubscribe*', '*/actions/*'],

    // Delivery overrides
    'stopSending' => false,
    'redirectAllTo' => '',
    'bccAll' => [],

    // Failure alerts
    'alertOnFailure' => false,
    'alertTo' => '',
    'alertThreshold' => 3,
    'alertWindow' => 60,           // minutes
    'alertCooldown' => 60,         // minutes
];

A multi-environment file works the same way as Craft's own:

return [
    '*' => ['retentionDays' => 60],
    'dev' => ['stopSending' => true, 'trackOpens' => false],
    'staging' => ['redirectAllTo' => 'qa@example.com'],
];

Logging

SettingDefaultWhat it does
enabledtrueThe master switch. Off, Corndog records nothing and changes nothing about how mail is sent — including the delivery overrides below.
storeHtmlBodytrueKeep the HTML body.
storeTextBodytrueKeep the plain-text body.
storeHeaderstrueKeep the message headers, including the ones your delivery service adds.
storeAttachmentDetailstrueRecord attachment names, types and sizes. Never the file itself.
maxBodySize512Longest body to store, in kilobytes. Anything longer is stored truncated, with a note where it was cut.

Privacy

SettingDefaultWhat it does
storeIpAddressestrueRecord the IP of whoever triggered the send, and of whoever opened a tracked message.
anonymiseIpAddressestrueBlur it: the last octet of an IPv4 address, the last 80 bits of an IPv6 one.

Blurring is on by default because the useful question is which office an email came from, not which desk. Turn it off only if you have a reason you could explain to the person whose address it is.

Retention

SettingDefaultWhat it does
retentionDays60Days to keep. 0 keeps everything forever, at whatever size that turns out to be.
maxRows5000Hard cap on rows; the oldest go first. 0 means no cap.

Both are applied together, age first, during Craft's garbage collection — so nobody's password reset pays for the trimming. Run it by hand with php craft corndog/email/prune.

A site that sends in bursts hits the row cap long before anything ages out. If the table is bigger than you want it to be, in order: lower maxRows, lower maxBodySize, then turn storeHtmlBody off. Bodies are the biggest thing in the table by an order of magnitude.

Tracking

SettingDefaultWhat it does
trackOpensfalseAdd a 1×1 image to HTML messages and count the loads.
trackClicksfalseRewrite links so clicks pass through your site and are counted.
ignoredLinkPatterns*unsubscribe*, */actions/*Globs for links that are never rewritten.

Both are off until you switch them on, and that is deliberate. Knowing whether a named person opened an email is personal data in most of the world, and a plugin that starts doing it on install has made a legal decision on your behalf. If you turn them on, say so in your privacy policy.

Unsubscribe links are excluded out of the box: routing that particular click through a tracker is tracking the one click somebody made specifically to stop being tracked. Add data-corndog-ignore to any individual link you want passed through untouched.

Delivery overrides

SettingDefaultWhat it does
stopSendingfalseLog every message and deliver none of them.
redirectAllTo''Replace every recipient with this address.
bccAll[]Blind-copy every outgoing message to these addresses.

stopSending is the switch for a staging site restored from a production database, where the addresses in it belong to real customers. The messages are logged in full, so you can read exactly what would have gone out.

Craft has testToEmailAddress in config/general.php, which does the same job as redirectAllTo. Use whichever fits where your settings live; if both are set, Craft's runs last and wins.

bccAll includes password resets. That is worth a moment's thought before you use it as an archive.

Failure alerts

SettingDefaultWhat it does
alertOnFailurefalseEmail somebody when sends start failing.
alertTo''Where the alert goes. Empty uses the system email address.
alertThreshold3Failures needed inside the window.
alertWindow60How far back the threshold counts, in minutes.
alertCooldown60Minimum minutes between two alerts.

One failure is usually a bad address; several together is usually the transport. The threshold is what keeps a typo from paging you.

The alert is sent through the same mailer that just failed, which is the obvious weakness of every alert of this kind. If the failure is the transport itself, the alert will not arrive either — so point alertTo at an address that does not depend on the same route where you can, and treat the alert as a bonus rather than as monitoring.