Campaign Logo Campaign

Send and manage email campaigns, contacts and lists.

Complete control and personalisation of emails using Twig templates.

Integrates seamlessly with Amazon SES, Mailgun, Mandrill, Sendgrid, etc.

Unlimited campaigns, subscribers, mailing lists and sendouts.

Cam­paign is an email mar­ket­ing plu­gin built spe­cific­ally for Craft 3. It aims to bring the dis­tri­bu­tion of con­tent by email into the CMS, where we believe it should be, along with the same eth­os of flex­ib­il­ity and user-friend­li­ness that Craft does.

Campaign integration

Listen to an interview with Philip Thygesen of Boomy share his experience moving a jobs website from Wordpress and Mailchimp to Craft and Campaign.

Watch the demo video:

Features #

Element Types
Campaigns, contacts, mailing lists, segments and sendouts are all element types. Composing your email campaigns and pulling in existing content is a cinch with custom fields.

Real-time Reports at your Fingertips
Detailed reports about your campaigns, contacts and mailing lists are available in real-time, right in the control panel.

Complete Control with Twig Templates
Complete personalisation of emails using Twig templates and variables. Design email templates for your specific site’s and client’s content needs.

Contact Management
Manage your contacts just like users. Import and export contacts easily from and to CSV files. Bounce and complaint handling is built-in to prevent email blacklisting.

Powerful Contact Segmentation
In addition to mailing lists, you also have fine-grain control over your contacts with segments. Segments are sets of conditions that filter contacts by specific fields, operators and values that can contain an unlimited amount of AND/OR conditions.

License #

This plugin requires a commercial license purchasable through the Craft Plugin Store. The license fee for the Lite version is $149 plus $49 per subsequent year for updates (optional). The license fee for the Pro version is $249 plus $79 per subsequent year for updates (optional).

Pro Version #

The following features are available exclusively in the Pro version of Campaign:

Requirements #

This plugin requires Craft CMS 3.1.0 or later.

The Story Behind Campaign #

We believe that while email marketing SaaS services such as MailChimp and Campaign Monitor fill an important gap, they are not necessarily the best choice when your content already exists in a CMS. With Craft, your content can be beautifully modular and reusable, so why would you (or your clients) ever want to have to copy-paste and reformat content into an email? We believe that the entire experience of creating, sending and monitoring campaigns, as well as managing contacts and mailing lists, belongs in the CMS.

In 2012 we built and released FireMail, an ExpressionEngine add-on which has been used on hundreds of websites. FireMail allows CMS users to send and monitor email campaigns, yet because of the technical limitations of the framework that it was built on, it suffers in performance and scalability when used on high-traffic sites with large mailing lists. We toyed with the idea of building a similar plugin for Craft 2 when it was released, yet it wasn’t until the release of Craft 3 beta that we made the decision to build the Campaign plugin. As developers who care tenaciously about attention to detail, we were and we remain dedicated to creating flexible, scalable and performant software.

Using Campaign #

To install the plugin, search for “Campaign” in the Craft Plugin Store, or install manually using composer.

composer require putyourlightson/craft-campaign

Requirements #

The Campaign plugin requires Craft CMS 3.1.0 or later.

Setting Things Up #

  1. Turn on “Test Mode” to disable live sending of emails in Campaign → Settings → General Settings.
  2. Adjust your email settings in Campaign → Settings → Email Settings.
  3. Add any custom fields you would like to contacts in Campaign → Settings → Contact Settings.
  4. Enable GeoIP if you would like to geolocate contacts by their IP addresses in Campaign → Settings → GeoIP Settings.
  5. Create at least one campaign type in Campaign → Settings → Campaign Types.
  6. Create at least one mailing list type in Campaign → Settings → Mailing List Types.
  7. Create a cron job on your web server as explained in Campaign → Settings → General Settings.

Getting Started #

  1. Create a new campaign in Campaign → Campaigns.
  2. Create a new mailing list in Campaign → Mailing Lists.
  3. Add contacts to your mailing list using one or more of the following techniques:
    • Create contacts in Campaign → Contacts and manually subscribe them in the Mailing Lists tab.
    • Import contacts from a CSV file in Campaign → Contacts → Import.
    • Import contacts from a user group in Campaign → Contacts → Import.
    • Sync contacts from users by syncing a mailing list with a user group in Campaign → Contacts → Sync (Pro version only).
  4. Create a new sendout in Campaign → Sendouts.

Testing #

Before sending to large mailing lists it is important to test that your campaign is correctly set up. By enabling on “Test Mode” in Campaign → Settings → General Settings, live sending of emails will be disabled and sendout emails will instead be saved into local files (in storage/runtime/debug/mail) rather that actually being sent. You can also send a test email on both the campaign as well as the sendout edit page. Email testing services such as Mailtrap can also be used for testing sendouts.

Email Delivery #

Campaign has its own email settings and can use any email delivery service that Craft supports. Craft natively supports Sendmail, SMTP and Gmail, and there are many plugins freely available which add third-party integrations (see “Mailer Transports” in the plugin store). SMTP can generally be used with most email delivery services, however using an API usually results in better performance, therefore the following plugins are recommended:

  1. Amazon SES by PutYourLightsOn
  2. Mailgun by Pixel & Tonic
  3. Mandrill by Pixel & Tonic
  4. Postmark by Pixel & Tonic
  5. SendGrid by PutYourLightsOn

Bounce and Complaint Handling #

Campaign includes webhooks to handle bounce and complain notifications for the following services:

  1. Amazon SES
  2. Mailgun
  3. Mandrill
  4. Postmark
  5. Sendgrid

To set up webhooks, copy the appropriate webhook URL from Campaign → Settings → General Settings and add it to the service you use (view each service’s documentation for instructions).

Multi-Site Functionality #

Campaign works with a multi-site set up by allowing campaigns, mailing lists, segments and sendouts to each be assignable to one and only one site. This enables the management of each of the above elements on a site by site basis.

Email Templates #

Email templates are defined in the campaign type’s settings page. A HTML as well as a plaintext email template should be provided that exist in the site’s templates folder.

The following template tags are available to email templates: campaign, browserVersionUrl, contact, unsubscribeUrl

Sample Code #

The following sample code shows how the tags can be used. Checking for the existance of the tags will ensure that they are only output when not blank, as may be the case for test emails and web versions.

{% if browserVersionUrl %}
  <a href="{{ browserVersionUrl }}">View this email in your browser</a>
{% endif %}

{% if contact.firstName %}
  Hello {{ contact.firstName }},
{% endif %}

Welcome to this month's newsletter in which we have some fascintaing announcements!

{{ campaign.announcements }}

{% if unsubscribeUrl %}
  <a href="{{ unsubscribeUrl }}">Unsubscribe from this mailing list</a>
{% endif %}

Designing Templates #

The majority of email clients either offer no support at all for CSS and floated elements or are inconsistent in how they display them, so email templates should be built using tables. Since designing, building and testing a reliable email template (that works in all email clients) can be a daunting, time-consuming task, we’ve collected some recommended resources that provide lots of useful information as well as some links to free tried-and-tested email templates that you can customise to your specific needs.

MJML #

We recommend using MJML, a markup language and framework for building responsive email templates. The free MJML desktop app makes coding email templates quick and easy. Watch the video below created by Philip Thygesen of Boomy.

If you would like to integrate MJML with Craft CMS then there is also the MJML plugin by Superbig.

Frameworks #

Foundation for Emails 2 is a framework for building responsive email templates using CSS or SASS without having to code tables by hand.
https://foundation.zurb.com/emails.html

Guides #

A step-by-step guide to creating email templates by EmailMonks.
https://emailmonks.com/blog/email-coding/step-step-guide-create-html-email/

A comprehensive guide to coding email templates by Campaign Monitor.
https://www.campaignmonitor.com/dev-resources/guides/coding/

A complete guide to coding email template and email marketing in general by MailChimp (some things are specific to MailChimp).
https://templates.mailchimp.com/

The “Ultimate Guide to Email Optimization + Troubleshooting” by Litmus.
https://litmus.com/lp/email-optimization-tips

HTML Templates #

Zurb offers an excellent range of free responsive HTML email templates that you can easily customise to match your site’s design.
https://foundation.zurb.com/emails/email-templates.html Zurb

Litmus offers a wide range of free HTML email templates that you can easily customise yourself or using the Litmus Builder.
https://litmus.com/community/templates Litmus

Testing #

A complete breakdown of the CSS support for the most popular mobile, web and desktop email clients.
https://www.campaignmonitor.com/css/

As well as offering many useful resources, Litmus allows you to design and test your email templates in all major email clients.
https://litmus.com/

Front-End Forms #

The following front-end forms are available so that you can allow contacts to take certain actions.

To avoid spam, we recommend you enable reCAPTCHA in Campaign → Settings → reCAPTCHA Settings or use the excellent Snaptcha plugin.

Subscribe Form #

You can create a mailing list subscribe form as follows.

{% set mailingList = craft.campaign.mailingLists.id(7).one() %}

<form id="subscribe-form" method="post" action="">
    {{ csrfInput() }}
    <input type="hidden" name="action" value="campaign/forms/subscribe" />
    <input type="hidden" name="mailingList" value="{{ mailingList.slug }}" />
    <input type="hidden" name="redirect" value="{{ 'subscribe-success'|hash }}" />

    <h3><label for="email">Email</label></h3>
    <input id="email" type="email" name="email" value="" required />

    <h3><label for="name">First Name</label></h3>
    <input id="name" type="text" name="fields[firstName]" value="" required />

    <h3><label for="name">Last Name</label></h3>
    <input id="name" type="text" name="fields[lastName]" value="" required />

    <h3><label for="name">Other Custom Field</label></h3>
    <input id="name" type="text" name="fields[customFieldName]" value="" />

    <!-- Required if reCAPTCHA is enabled in plugin settings -->
    {{ craft.campaign.recaptcha }}

    <input type="submit" value="Subscribe" />
</form>

To submit the form using an AJAX request, you’ll need to send a POST request containing the fields. Here’s an example using jQuery.post().

<script>
    // Get data by serializing the form
    var data = $('#subscribe-form').serialize();

    // Post the data to the current URL
    $.post('', data, function(response) {
        if (response.success) {
            alert('You have successfully subscribed to the mailing list.');
        }
        else {
            alert(response.error);
        }
    });
</script>

Unsubscribe Form #

You should always make it possible for contacts to unsubscribe from a mailing list by providing them with an unsubscribe link in campaigns.

You can additionally create a mailing list unsubscribe form as follows. The Unsubscribe Form Allowed setting must be enabled in the mailing list type for this to work.

{% set mailingList = craft.campaign.mailingLists.id(7).one() %}

<form id="unsubscribe-form" method="post" action="">
    {{ csrfInput() }}
    <input type="hidden" name="action" value="campaign/forms/unsubscribe" />
    <input type="hidden" name="mailingList" value="{{ mailingList.slug }}" />
    <input type="hidden" name="redirect" value="{{ 'unsubscribe-success'|hash }}" />

    <h3><label for="email">Email</label></h3>
    <input id="email" type="email" name="email" value="" required />

    <!-- Required if reCAPTCHA is enabled in plugin settings -->
    {{ craft.campaign.recaptcha }}

    <input type="submit" value="Unsubscribe" />
</form>

If you have contacts that are synced to users then you can provide them with a way to unsubscribe provided they are logged in.

{% set contact = craft.campaign.contacts.userId(currentUser.id).one() %}
{% set mailingLists = contact.getMailingLists() %}

{% for mailingList in mailingLists %}
    <form id="unsubscribe-form" method="post" action="">
        {{ csrfInput() }}
        <input type="hidden" name="action" value="campaign/contacts/unsubscribe-mailing-list" />
        <input type="hidden" name="contactId" value="{{ contact.id }}" />
        <input type="hidden" name="mailingListId" value="{{ mailingList.id }}" />

        <input type="submit" value="Unsubscribe" />
</form>
{% endfor %}

Contact Update Form #

You can create a contact update form as follows. Note that the contact’s cid and uid are both required in order to authenticate the request.

{% set contact = craft.campaign.contacts.userId(currentUser.id).one() %}

<form id="update-form" method="post" action="">
    {{ csrfInput() }}
    <input type="hidden" name="action" value="campaign/forms/update-contact" />
    <input type="hidden" name="cid" value="{{ contact.cid }}" />
    <input type="hidden" name="uid" value="{{ contact.uid }}" />

    <h3><label for="name">First Name</label></h3>
    <input id="name" type="text" name="fields[firstName]" value="{{ contact.firstName }}" required />

    <h3><label for="name">Last Name</label></h3>
    <input id="name" type="text" name="fields[lastName]" value="{{ contact.lastName }}" required />

    <h3><label for="name">Other Custom Field</label></h3>
    <input id="name" type="text" name="fields[customFieldName]" value="{{ contact.customFieldName }}" />

    <!-- Required if reCAPTCHA is enabled in plugin settings -->
    {{ craft.campaign.recaptcha }}

    <input type="submit" value="Update" />
</form>

Campaigns #

Campaigns, just like entries, have their own custom field layout (limited to a single tab), determined by the campaign type they belong to. They each have their own URL and work with live preview. A campaign can be sent to one or more mailing lists by creating and assigning it to a sendout.

Campaign Types #

Before you can create a campaign, you must create at least one campaign type. Each campaign type lets you define a custom field layout a well as the following settings.

Campaign URI Format #

What the campaign URIs should look like. You can include tags that output campaign properties.

newsletter/{slug}

HTML Template #

The HTML template to use when a campaign’s URL is requested, located in the main templates folder.

_newsletter/html

Plaintext Template #

The plaintext template to use when sending a plaintext version, located in the main templates folder.

_newsletter/plaintext

To create a new campaign type, go to Settings → Campaign Types and click the “New campaign type” button.

Campaign Template Variables #

You have access to the following variables in your campaign templates.

campaign #

The current campaign.

contact #

The contact that received the campaign. This will be null if there is no contact, so you should always test for it in your templates before outputting properties.

sendout #

The sendout that sent the campaign. This will be null if there is no sendout, so you should always test for it in your templates before outputting properties.

browserVersionUrl #

The URL to the browser version of the campaign.

unsubscribeUrl #

The URL to unsubscribe from the mailing list that the campaign was sent to.

<h1>{{ campaign.title }}</h1>

{% if contact %}
    <p>Hello {{ contact.name }}</p>
{% endif %}

{{ campaign.body }}

<a href="{{ browserVersionUrl }}">View this email in your browser</a>

{% if unsubscribeUrl %}
    <a href="{{ unsubscribeUrl }}">Unsubscribe here</a>
{% endif %}

Getting Campaigns #

You can get campaigns from your templates with craft.campaign.campaigns which returns an Element Query.

// Gets all campaigns that are of the specified campaign type
{% set campaigns = craft.campaign.campaigns.campaignType('newsletter').all() %}

{% for campaign in campaigns %}
   <a href="{{ campaign.url }}">{{ campaign.title }}</a>
{% endfor %}

You can get campaigns from your plugin with CampaignElement::find() which returns an Element Query.

use putyourlightson\campaign\elements\CampaignElement;

$campaigns = CampaignElement::find()->campaignType('newsletter')->all();

In addition to supporting the parameters that all element types in Craft support (id, title, etc.), the returned Element Query also supports the following parameters.

campaignType #

Only fetch campaigns that belong to a given campaign type(s). Accepted values include a campaign type handle, an array of campaign type handles, or a CampaignTypeModel object.

campaignTypeId #

Only fetch campaigns that belong to a given campaign type(s), referenced by its ID.

Outputting Campaigns #

In addition to having the properties that all element types in Craft have (id, title, etc.), campaigns also have the following properties and methods.

Properties #

bounced #

The number of contacts that have bounced from the campaign.

campaignTypeId #

The campaign’s campaign type ID.

campaignType #

Alias of getCampaignType().

clicked #

The number of contacts that have clicked on a link in the campaign.

clicks #

The number of times that the campaign was clicked.

clickThroughRate #

Alias of getClickThroughRate().

complained #

The number of contacts that have complained about the campaign.

dateClosed #

A DateTime object representing the date the campaign was closed.

opened #

The number of contacts that have opened the campaign.

opens #

The number of times that the campaign was opened.

recipients #

The number of contacts that have received the campaign.

status #

The status (‘sent’, ‘unsent’, ‘closed’, ‘disabled’) of the campaign.

unsubscribed #

The number of contacts that have unsubscribed from the campaign.

Methods #

getCampaignType() #

Returns a CampaignTypeModel object representing the campaign’s campaign type.

getClickThroughRate() #

Returns the campaign’s click-through rate.

getHtmlBody( contact, sendout ) #

Returns the campaign’s HTML body, optionally with a contact and sendout.

getPlaintextBody( contact, sendout ) #

Returns the campaign’s plaintext body, optionally with a contact and sendout.

Contacts #

Contacts, just like users, have their own custom field layout (limited to a single tab). They can be subscribed to multiple mailing lists and can be segmented using conditions. They can be imported from CSV files and user groups, exported in CSV format and synced to users.

Creating Contacts #

To create a new contact manually, go to the Contacts page and click the “New contact” button. Once saved, you can then manually subscribe or unsubscribe the contact from mailing lists in the Mailing Lists tab of the contact edit page.

To import contacts in bulk, go to Contacts → Import and select a CSV file or a user group to import from.

To export contacts to a CSV file, go to Contacts → Export and select a mailing list and the fields to export.

To sync contacts with users, go to Contacts → Sync and select a mailing list and user group to sync. Every time a user in the selected user group is created, updated or deleted, the contact in the synced mailing list will also be created, updated or removed accordingly. All custom fields that exist for contacts will be populated from the user fields. If you want users’ first and last names to be synced then you should create custom fields with the handles firstName and lastName respectively and assign them to contacts before performing the sync. Modifications to contacts will NOT affect users.

Getting Contacts #

You can get contacts from your templates with craft.campaign.contacts which returns an Element Query.

// Gets the first contact with the specified email address
{% set contact = craft.campaign.contacts.email('[email protected]').one() %}

{% if contact %}
   <a href="mailto: {{ contact.email }}">{{ contact.name }}</a>
{% endif %}

You can get contacts from your plugin with ContactElement::find() which returns an Element Query.

use putyourlightson\campaign\elements\ContactElement;

$contact = ContactElement::find()->email('[email protected]')->one();

In addition to supporting the parameters that all element types in Craft support (id, title, etc.), the returned Element Query also supports the following parameters.

userId #

Only fetch a contact that is synced to the given user ID.

cid #

Only fetch a contact with the given CID (unique contact ID).

email #

Only fetch a contact with the given email address.

mailingListId #

Only fetch contacts with the given mailing list ID.

segmentId #

Only fetch contacts with the given segment ID.

Outputting Contacts #

In addition to having the properties that all element types in Craft have (id, title, etc.), contacts also have the following properties and methods.

Properties #

bounced #

A DateTime object representing the date that the contact bounced.

cid #

The contact’s CID (unique contact ID).

client #

The last client (web browser) that was detected for the contact.

complained #

A DateTime object representing the date that the contact complained.

country #

The last country that was detected for the contact.

device #

The last device that was detected for the contact.

email #

The contact’s email address.

lastActivity #

A DateTime object representing the date that the contact was last active.

verified #

A DateTime object representing the date that the contact verified their email address (applies for double opt-in only).

status #

The status (‘active’, ‘complained’, ‘bounced’) of the contact.

os #

The last OS (operating system) that was detected for the contact.

Mailing Lists #

Mailing lists have their own custom field layout (limited to a single tab), determined by the mailing list type they belong to. They can contain an unlimited amount of subscribed contacts.

Mailing List Types #

Before you can create a mailing list, you must create at least one mailing list type. Each mailing list type lets you define a custom field layout a well as the following settings.

Double Opt-In #

Whether the user needs to verify their email address by clicking on a link in an email that will be sent to them (recommended for security).

Verify Email Template #

The template to use for the verification email that is sent to users if double opt-in is enabled (leave blank for default message template). Available template tags: url, mailingList.

Verify Success Template #

The template to use when a user verifies their email address if double opt-in is enabled (leave blank for default message template). Available template tags: mailingList.

Subscribe Success Template #

The template to use when a user subscribes to a mailing list (leave blank for default message template). Available template tags: mailingList.

Unsubscribe Success Template #

The template to use when a user unsubscribes from a mailing list (leave blank for default message template). Available template tags: mailingList.

To create a new mailing list type, go to Settings → Mailing List Types and click the “New mailing list type” button.

Getting Mailing Lists #

You can get mailing lists from your templates with craft.campaign.mailingLists which returns an Element Query.

// Gets the first mailing list with the specified ID
{% set mailingList = craft.campaign.mailingLists.id(7).one() %}

{% if mailingList %}
   Subscribe to {{ mailingList.title }}
{% endif %}

You can get mailing lists from your plugin with MailingListElement::find() which returns an Element Query.

use putyourlightson\campaign\elements\MailingListElement;

$mailingList = MailingListElement::find()->id(7)->one();

In addition to supporting the parameters that all element types in Craft support (id, title, etc.), the returned Element Query also supports the following parameters.

mailingListType #

Only fetch mailing lists that belong to a given mailing list type(s). Accepted values include a mailing list type handle, an array of mailing list type handles, or a MailingListTypeModel object.

mailingListTypeId #

Only fetch mailing lists that belong to a given mailing list type(s), referenced by its ID.

Outputting Mailing Lists #

In addition to having the properties that all element types in Craft have (id, title, etc.), mailing lists also have the following properties and methods.

Properties #

mailingListTypeId #

The mailing list’s mailing list type ID.

Segments #

Segments (Pro version only) are sets of conditions that filter contacts by specific fields, operators and values. They can contain an unlimited amount of AND and OR conditions, and can be applied to sendouts.

Segment Types #

The types of conditions available to segments are determined by the segment type they belong to.

Regular #

With regular segments, conditions can be combined by logical AND and OR operators in order to create a very unique segmentation of contacts. Each supported contact field offers a different operator and value format, for example plaintext fields allow string comparisons while date fields allow date comparisons.

Segment Conditions

Template #

Template segments provide a textarea in which you can add as much twig template code as you want. The template should output a string that evaluates to true (anything except for 0 or a blank string). The contact tag is available in this context.

{{ contact.dateOfBirth|date('Y') == 1980 ? 1 : 0 }}

Note that template conditions require processing template code for every contact and can therefore slow down the sending process. Use them sparingly and only when a regular segment is insufficient.

Segment Template

Getting Segments #

You can access segments from your templates with craft.campaign.segments which returns an Element Query.

// Gets the first segment with the specified ID
{% set segment = craft.campaign.segments.id(3).one %}

{% if segment %}
   Segment {{ segment.title }}
{% endif %}

You can get segments from your plugin with SegmentElement::find() which returns an Element Query.

use putyourlightson\campaign\elements\SegmentElement;

$segment = SegmentElement::find()->id(3)->one();

The returned Element Query supports the parameters that all element types in Craft support (id, title, etc.).

Sendouts #

Sendouts are how you send campaigns to your mailing lists. Sendouts can be sent immediately, on a scheduled date and time, or at a specific delayed interval after a contact subscribes to a mailing list.

Sendout Types #

The time at which sendouts are sent is determined by the sendout type they belong to.

Regular #

Regular sendouts are queued for sending immediately after being saved and sent.

Scheduled #

Scheduled sendouts allow you an exact date and time on which to send a campaign. As soon as the send date is reached, the sendout will be queued for sending.

Note: Scheduled sendouts require that you create a cron job as described in Settings → General Settings.

Scheduled Sendout

Automated #

Automated sendouts (Pro version only) allow you to automate the delayed sending of a campaign to contacts, a specific amount of time after they subscribe to one or more mailing lists. As soon as the delayed period of time has passed, the sendout will be automatically queued for sending according to the schedule that you set.

Note: Automated sendouts require that you create a cron job as described in Settings → General Settings.

Automated Sendout

Recurring #

Recurring sendouts (Pro version only) allow you to automate the sending of a campaign to contacts on a recurring schedule. You must consider and select whether the sendout can be sent to contacts multiple times. The sendout will be automatically queued for sending according to the schedule that you set.

Note: Recurring sendouts require that you create a cron job as described in Settings → General Settings.

Recurring Sendout

How Sendouts Are Sent #

Once a sendout is queued for sending, it will begin sending the next time that the queue is run. If Craft’s runQueueAutomaticallyconfig setting is set to true (the default value), then this will happen immediately, otherwise it will happen the next time the queue is run (initiated from a cron job, for example). The sendout is sent in a background process, so the site will remain usable for all visitors.

Running Pending Sendouts #

Sendouts that are not immediately sent (scheduled, automated or recurring), require a cron job in order to be queued and run at the appropriate time. If you plan on using these sendout types then you should create a cron job to run pending sendouts on a scheduled basis (every 10 minutes for example). Change /usr/bin/php to your PHP path (if different) and /var/www/my_craft_project to your craft project path.

*/10 * * * * /usr/bin/php /var/www/my_project/craft campaign/sendouts/run-pending-sendouts

Warning: when using the console command, the @web alias is unavailable and will return a blank string. For that reason, is it better avoid using the @web alias in your site and asset volume settings.

You can queue pending sendouts with a controller action through a unique URL, see Settings → General Settings. You can also manually queue pending sendouts at any time using the utility at Utilities → Campaign.

A command line utility can also be used to queue and run pending sendouts with the following console command:

./craft campaign/sendouts/run-pending-sendouts

Delayed Batch Sending #

In order to avoid a timeout or the memory limit being exceeded while sending, the plugin will initiate a new delayed batch job when it exceeds a threshold of either of the limits. The thresholds, the limits, the max batch size and the batch job delay can all be defined in the plugin’s config settings.

// The threshold for memory usage per sendout batch as a fraction
'memoryThreshold' => 0.8,

// The threshold for execution time per sendout batch as a fraction
'timeThreshold' => 0.8,

// The memory usage limit per sendout batch in bytes or a shorthand byte value (set to -1 for unlimited)
'memoryLimit' => '1024M',

// The execution time limit per sendout batch in seconds (set to 0 for unlimited)
'timeLimit' => 300,

// The max size of sendout batches
'maxBatchSize' => 1000,

// The amount of time in seconds to delay jobs between sendout batches
'batchJobDelay' => 10,

Getting Sendouts #

You can access sendouts from your templates with craft.campaign.sendouts which returns an Element Query.

// Gets all sendouts that were sent to the campaign with the specified ID
{% set sendouts = craft.campaign.sendouts.sendoutType('sent').campaignId(5).all %}

{% for sendout in sendouts %}
   {{ sendout.title }} sent on {{ sendout.sendDate|date }}
{% endfor %}

You can get sendouts from your plugin with SendoutElement::find() which returns an Element Query.

use putyourlightson\campaign\elements\SendoutElement;

$sendouts = SendoutElement::find()->sendoutType('sent')->campaignId(5)->all();

In addition to supporting the parameters that all element types in Craft support (id, title, etc.), the returned Element Query also supports the following parameters.

sid #

Only fetch sendouts with the given SID (unique sendout ID).

sendoutType #

Only fetch sendouts with the given sendout type (regular / scheduled / automated).

campaignId #

Only fetch sendouts with the given campaign ID.

mailingListId #

Only fetch sendouts with the given mailing list ID.

segmentId #

Only fetch sendouts with the given segment ID.

Integrations #

You can easily integrate your plugin with Campaign by using any of the available elements in src/elements or the service classes in src/services.

Getting/Creating a Contact #

Before creating a contact, you should always check if one already exists with the same email address.

$contact = Campaign::$plugin->contacts->getContactByEmail('[email protected]');

if ($contact === null) {
    $contact = new ContactElement();
    $contact->email = '[email protected]';
    $contact->customFieldName = $customFieldValue;
}

Craft::$app->getElements()->saveElement($contact)

Subscribing a Contact to a Mailing List #

You can subscribe a contact to a mailing list using the subscribe method of the TrackerService class.

$mailingList = MailingListElement::find()->slug($mailingListSlug)->one();

if ($mailingList === null) {
    throw new NotFoundHttpException(Craft::t('campaign', 'Mailing list not found'));
}

$source = Craft::$app->getRequest()->getReferrer();

Campaign::$plugin->tracker->subscribe($contact, $mailingList, 'web', $source);

Data Privacy #

Campaign gives you full control over your contacts. Deleting a contact will completely and permanently remove all of its data and activity from the database.

In addition to any custom fields that you have created and assigned to contacts, the Campaign plugin stores campaign and mailing list activity about contacts, as well as the following data.

email #

The contact’s email address.

country #

The country that the contact was last active from (if GeoIP is enabled).

geoIp #

The GeoIP location that the contact was last active from (if GeoIP is enabled), specifically:
continentCode, continentName, countryCode, countryName, regionCode, regionName, city, postCode, timeZone

device #

The device that the contact was last active from.

os #

The OS (operating system) that the contact was last active from.

client #

The web browser client that the contact was last active from.

lastActivity #

A timestamp of the contact’s last activity.

complained #

A timestamp of the contact’s spam complaint.

bounced #

A timestamp of the contact’s bounced email.

verified #

A timestamp of the contact’s verified email (through double opt-in).