GreenArrow Documentation

Special Sending Rules

Overview

Special Sending Rules provide a way to programmatically customize the sending attributes or the content of a message before it is sent.

When a Special Sending Rule is configured for an email campaign a function is called to customize each message. This function is given data about what will be sent and can return data to override the sending attributes or content of the message.

Special Sending Rule code is called once per message.

Special Sending Rules: Usage & Interface

Notes

  • Only System Admin users may create or update Special Sending Rules.
  • Special Sending Rules may be applied to mailing lists as a campaign default. New campaigns will use that SSR as a default.
  • Special Sending Rules may be applied to campaigns.
  • If a Special Sending Rule returns a Virtual MTA, Bounce Email, or URL Domain that does not exist (by name, not ID) in GreenArrow Engine, it will cause the campaign to fail.
  • In PHP, the timezone defaults to the system time zone - often this is “US/Central”. To change this, see date_default_timezone_set.

Attributes of a Special Sending Rule

Name — This is the identifier that you’ll use within GreenArrow Studio to select this SSR.

Number of Workers — This value determines how many processes are run to execute this SSR. If the SSR is simple with low CPU usage, this can safely be set to the default (2). If you have an SSR that is complex or slow, this can be increased to improve overall performance. The maximum value for this field is determined by the Max SSR Workers system configuration.

Language — The programming language to evaluated the SSR in. Perl and PHP are supported.

Code — This is the computer code that is executed to determine this SSR’s functionality.

Managing Special Sending Rules

Viewing the List of Special Sending Rules

In the Admin top navigation, click on the SSRs sub-navigation link.

Creating a New Special Sending Rule

  1. In the Admin top navigation, click on the SSRs sub-navigation link.
  2. Click Create a special sending rule.
  3. Fill in this form with the correct details. See the documentation below to know how to declare the SSR function.
  4. Click Create this special sending rule.

Previewing a Special Sending Rule

To see what effect an SSR will have on a campaign, navigate to the SSR’s show page and do the following.

  1. Click the Preview this special sending rule button.
  2. Select an organization, campaign, and subscriber details to use.
  3. Click the View preview button.

The resulting page details what the SSR did. If there is an error or exception thrown by the code, it is shown on this page.

If the selected campaign has a split-test, the preview will run for the first defined content.

Special Sending Rules in Campaign Preview Emails

If a campaign is configured to use a Special Sending Rule, that rule is applied to campaign preview emails as well.

The Special Sending Rule evaluation and preview email have the following details:

  • The recipient’s email address is the address specified when creating the preview.
  • The recipient’s custom fields are the mailing list’s Preview and Seed Custom Field Values.
  • Any custom headers that you specify get included, with the exception of the List-Unsubscribe header.
  • If no segment is set for the campaign, null values are passed to the Special Sending Rule for segment fields.
  • Other delivery details are pulled from the campaign. If no delivery details are set, then the system Campaign Preview Defaults values are used.
  • The preview delivery default Virtual MTA will always be used, regardless of if the campaign or Special Sending Rule overrides it.
  • Any errors in the Special Sending Rule are shown when creating the preview email.

System and Organization Configuration

Setting the Max SSR Workers Value

In order to prevent individual SSRs from being configured to use too many processes, in the System Configuration screen you may set a Max SSR Workers value. This is the maximum number of workers that any individual SSR may allocate.

Organization Permissions

Special Sending Rules are disabled by default for all organizations other than the System Organization. System administrators may navigate to an organization’s page to grant or revoke access to SSRs, with the following caveats.

  • This is an “all or nothing” option - turning on Special Sending Rules for an organization grants them access to all of them
  • If you remove access to SSRs for an organization which has any autoresponders, not-yet-started campaigns or mailing lists that use a Special Sending Rule, then the Special Sending Rule setting for those campaigns or autoresponders is cleared.
    • This can change the email that is sent by these autoresponders, campaigns, and/or mailing lists, so a confirmation message is shown on the organization edit page confirming the change.
    • When an autoresponder or campaign is updated in this way, a note is added to their history about the update.
  • Campaigns that start sending with an SSR and do not have permissions to an SSR (e.g. a campaign was set up with SSR permissions, started sending with SSR permissions, then was paused after permissions were revoked, and later resumed) fail with a note in the campaign history log
  • If an autoresponder or campaign has an SSR and the organization doesn’t have SSR permissions, still show it in the campaign’s view page with the (invalid) suffix
  • If an autoresponder or campaign has an SSR and the organization doesn’t have SSR permissions, still show it in the edit page for that object, but they may only select None - show the current SSR with the (invalid) suffix

Campaign Preview Emails

If a campaign is configured to use a Special Sending Rule at the time a preview email is requested, the SSR is evaluated on that preview email.

Special Sending Rules: Development

Conventions in this Document

This document describes methods in multiple computer languages which use different terms for similar things. Here is how the concepts are translated.

In this document Perl PHP
Hash Hash reference Array
Undefined undef null

Details and Limitations

For Special Sending Rules used in campaigns:

  • A Special Sending Rule may run for a maximum of 60 seconds before being terminated, potentially causing the campaign to fail.
  • Special Sending Rules are attempted three times before causing processing the subscriber to fail.
  • The first retry is 10 seconds later, with the second retry 60 seconds after that.
  • Depending on the configuration of the Special Sending Rule, either:
    • A single error processing a subscriber will cause the campaign to be stopped
    • An error threshold must be exceeded for the campaign to be stopped (For example, greater than 10% of subscribers with errors in the last 2 minutes.)
  • The Number of Workers field in Special Sending Rules defines the parallelism of the SSR. Every campaign that is using this SSR will run that many instances of the evaluator process.
  • Each Special Sending Rule process will handle multiple messages - but will occasionally be restarted in order to reduce the danger of memory leaks in custom code. For this reason, you may use global variables in order to optimize for speed (for example, fetching a resource from an HTTP request and storing it in a global); but you should not assume that an SSR is only started once per campaign. A Special Sending Rule might be loaded many times over the course of a campaign.

For Special Sending Rules used in autoresponders and web-forms:

  • A Special Sending Rule may run for a maximum of 60 seconds before being terminated, potentially causing the message to be skipped.
  • An error will not cause a retry.
  • Errors are logged to the autoresponder or web-form history page.
  • Currently, each Special Sending Rule process will handle a single message. This may change in the future to allow one process to handle multiple messages.
  • Because there is little parallelism in SSR evaluation and the error handling is not as robust as campaigns, it is strongly recommended to not access any external resources or do any time-intensive processing.

Definition of Data In and Out of Special Sending Rules

Data Provided to the Special Sending Rule

Campaign Information Hash

The Campaign Information Hash ($campaign_information_hash) contains data about the campaign. This does not change per recipient:

Key Description
entity_type The type of message that is being delivered. May be campaign, autoresponder, or web_form.
is_preview If this is a campaign preview, then 1. Otherwise 0.
seed_list_id Deprecated: The ID of the first seed list assigned to the Campaign, ordered by ID. Use seed_lists instead. (Undefined if no seed list selected.)
seed_list_name Deprecated: The name of the first seed list, ordered by ID. (Undefined if no seed list selected.)
seed_lists An array of seed lists used for the campaign. Each entry is a hash with id and name keys.
speed Speed of the campaign in messages per hour or zero if unlimited.
from_name From address name.
from_email From email address.
sender_email Sender email address. (Undefined if not specified.)
reply_to Reply-To email address (Undefined if not specified.)
virtual_mta_name Name of VirtualMTA used for sending. (If this option is hidden from the user, then this is set to the actual value used for sending.)
virtual_mta_id Primary key of the VirtualMTA.
url_domain_name Domain name for click and open tracking URLs. (If this option is hidden from the user, then this is set to the actual value used for sending.)
url_domain_id Primary key of the URL Domain.
track_opens If tracking opens, then 1. Otherwise 0.
track_links If tracking links, then 1. Otherwise 0.
bounce_email Bounce handling email address. (If this option is hidden from the user, then this is set to the actual value used for sending.)
mailing_list_name Name of mailing list.
mailing_list_id Primary key of mailing list.
segmentation_criteria_name The name of the segment used for this campaign.
segmentation_criteria_id The id of the segment used for this campaign.
segmentation_criteria_json The JSON blob that defines the segment used for this campaign (applies to Standard Mailing Lists).
segmentation_criteria_sql The SQL query used to retrieve the recipient list for this campaign (applies to Remote Lists).

Note on segmentation_criteria_json: The format of this field is undocumented. It exists as an input for users that need it, but its fields should be discovered through experimentation. (If a campaign does not yet have a segment defined, then these values are null. This can happen when a SSR is applied to a campaign preview where the campaign does not have a segment defined.)

For campaigns, the following extra keys are present.

Key Description
campaign_name Name of campaign.
campaign_id Primary key of campaign.

For autoresponders, the following extra keys are present.

Key Descriptioni
autoresponder_name Name of autoresponder.
autoresponder_id Primary key of autoresponder.

For web forms, the following extra keys are present.

Key Description
web_form_name Name of web form.
web_form_id Primary key of web form.

Recipient Information Hash

The Recipient Information Hash ($multiple_recipients_information_hash) contains two hashes:

Key Description
subscriber Information about the recipient of the email message. (Defined below.)
content Information about the content to be sent. This is not part of the campaign information hash, because with split A/B testing a campaign can send different content versions to different subscribers. (Defined below.)
subscriber Hash
subscriber

hash


id

integer

Primary key of subscriber.

If this email is to a seed address, this is of the form seed-MD5 where MD5 is the lowercase MD5 of the recipient’s email address.

email

string

The subscriber’s email address.

If the subscriber’s email domain is an Internationalized Domain Name, the email address is provided in the “punycode” form. See the Subscriber Record documentation for more information on this. This behavior may change in the future.

created_at

string

Time subscriber record was created in ISO 8601 date/time format in the organization time zone.

created_at_epoch

integer

Time subscriber record was created in seconds past the UNIX epoch in the organization time zone.

created_at_epoch_utc

integer

Time subscriber record was created in seconds past the UNIX epoch in the UTC time zone.

confirmed

integer

If confirmed, then 1. Otherwise 0. This key is only shown for mailing lists which use the Confirmed field.

email_format

string

Subscriber’s format setting (html or text). This key is only shown for mailing lists which use the Format field.

status

string

Status for the subscriber. Is always active.

subscribe_time

string

Time that subscriber subscribed in ISO 8601 date/time format in the organization time zone.

subscribe_time_epoch

integer

Time that subscriber subscribed in seconds past the UNIX epoch in the organization time zone.

subscribe_time_epoch_utc

integer

Time that subscriber subscribed in seconds past the UNIX epoch in the UTC time zone.

subscribe_ip

string

IP address that subscriber subscribed from.

custom_fields

hash of hashes

Hash of custom fields. Uses the same format as returned by the get subscriber API call.

The date values are returned in YYYY-MM-DDThh:mm:ss.s format, using UTC as the time zone. For example, 2014-10-30 13:08:18.936708.

For Remote Lists, the meaning of the fields is the following:

  1. These fields are always NULL
    • created_at
    • created_at_epoch
    • created_at_epoch_utc
    • status
    • subscribe_time
    • subscribe_time_epoch
    • subscribe_time_epoch_utc
    • subscribe_ip
  2. These keys will never be present:
    • confirmed (remote lists can not have a confirmed field)
    • email_format (remote lists can not have a format field)
  3. The id field is the recipient’s sequence number during delivery.
  4. If the recipient has a distinct id, it is in the custom_fields["distinct_id"] value.
  5. The email field is recipient’s email address.
  6. The field names in custom_fields is lowercased.
content Hash
Key Description
id The internal ID of this content object
format Format of email message to send: both, html, or text
html HTML content before custom field replacement, click tracking, and open tracking. (If this is a text-only message, then this is undefined.)
text Text content before custom field replacement, click tracking, and open tracking. (If this is a html-only message, then this is undefined.)
subject Subject of email before custom field replacement.

Data Returned From the Special Sending Rule

Override Hash

Setting a key in the Override Hash (the return value of the Special Sending Rule) overrides the default value for a particular delivery.

html

string

message_information_hash.content.html

New HTML content. If this is set to undefined or a blank string, then this removes the HTML content and creates a text-only email, provided that text content exists. Custom field replacement, click tracking, and open tracking are performed on this content.

text

string

message_information_hash.content.text

New text content. If this is set to undefined or a blank string, then this removes the text content and creates a HTML-only email, provided that HTML content exists. Custom field replacement, and click tracking are performed on this content.

subject

string

message_information_hash.content.subject

New Subject. Custom field replacement are performed on this content.

from_name

string

campaign_information_hash.from_name

New From address name.

from_email

string

campaign_information_hash.from_email

New From email address.

sender_email

string

campaign_information_hash.sender_email

New Sender email address. Set to blank or undefined to clear the Sender email address.

reply_to

string

campaign_information_hash.reply_to

New Reply-To email address. Set to blank or undefined to clear the Reply-To email address.

virtual_mta_name

string

campaign_information_hash.virtual_mta_name

New VirtualMTA. Set to the name of the VirtualMTA. Specify only one of this or virtual_mta_id.

virtual_mta_id

string

campaign_information_hash.virtual_mta_id

New VirtualMTA. Set to the ID of the VirtualMTA. Specify only one of this or virtual_mta_name.

url_domain_name

string

campaign_information_hash.url_domain_name

New URL Domain. Set to the URL Domain domain name. Specify only one of this or url_domain_id.

url_domain_id

string

campaign_information_hash.url_domain_id

New URL Domain. Set to the ID of the URL Domain. Specify only one of this or url_domain_name.

bounce_email

string

campaign_information_hash.bounce_email

New Bounce email address. Specify only one of this or bounce_email_id.

bounce_email_id

string

New Bounce email address. Specify only one of this or bounce_email.

skip

string

A return value of true, 1, or a number greater than zero in this field will cause this recipient to be skipped in delivery.

skip_message

string

If provided, this message is set on the skip event and shown in the statistics screen.

attachments

string

An array of attachment hashes, as defined below.

custom_headers

string

A string of email headers that are added to the message (e.g. X-Data: User 123).

The following header names are allowed:

  • Names that begin with X-, but do not begin with X-Mailer-Info and contain only letters, numbers and dashes ([a-zA-Z0-9-])
  • List-Unsubscribe. If specified, this takes precedence over the List-Unsubscribe header that’s normally generated by Studio.
  • Require-Recipient-Valid-Since

Header values may contain only ASCII characters 32-126 ([\x20-\x7e] in hexadecimal).

Multiple headers may be specified by putting a newline between them (e.g. X-Data: User 123\nX-Alt: Option 4\n).

If no trailing newline is included, one is added. CRLF (\r\n) is converted to only LF (\n).

  • If the SSR’s override hash includes html or text keys, this may cause the email format to change. For example, if a campaign was originally text, but the SSR returns non-blank values for both html and text, a multipart/alternative email is sent instead of text/plain.
  • If the SSR returns blank values for both html and text, this will cause the delivery to fail because no content is available to send. Note that this only comes up if the override has defined those keys, removing the original content.
  • If a SSR returns a blank value for text on a text-only campaign, this will cause the delivery to fail because no content is available to send.

Attachment Hash

Each hash in the attachments array of the Override Hash must have the following keys:

Key Description
filename The string that is used as the filename in the attachment. Must not be blank.
content_type The string that is used as the MIME type for the attached file.
content The string that is used as the content of the attachment.
  • Filenames may contain the characters A-Z, a-z, 0-9, _, -, . and spaces, must be at least one character long, must contain at least one non-whitespace character, and may be at most 100 characters long.
  • If content_type is blank, it will default to application/octet-stream.

Here are some of the most common MIME Types used in email attachments. See the Wikipedia page on MIME Types for an expanded list of types.

MIME Type File Extension Description
text/plain .txt Plain Text
text/html .html HTML
application/pdf .pdf Adobe Acrobat Portable Document Format
application/msword .doc Microsoft Word
application/vnd.ms-excel .xls Microsoft Excel

Special Sending Rule Function Interface

General Structure

Your Special Sending Rule contains code that is run as part of a function by GreenArrow Studio. You don’t provide the syntax that defines the function/subroutine itself (such as function example ($arg) { statements... }), but rather just provide the source code lines (statements) to be run.

Input values are provided in variables already defined in the local context.

Data is returned by calling the return command. Not calling the return command will result in an error.

Input Variables

The following variables are defined in local context:

Variable Description
$campaign_information_hash Campaign Information Hash
$multiple_recipients_information_hash Multiple Recipients Information Hash

Campaign Information Hash

This is the Campaign Information Hash as defined above.

Multiple Recipients Information Hash

This is a hash that contains information on one or more recipients for the Special Sending Rule to process.

  • Key - The id of the subscriber (the numeric primary key).
  • Value - The recipient information hash (as defined above) with information on this subscriber and their email.

See examples below.

Expected Return Value

The Special Sending Rule returns a hash with override information for the current subscriber.

  • Key - The subscriber id (numeric primary key) of the subscriber to have overrides performed on their email. This subscriber id must have been provided as part of the Multiple Recipients Information Hash that was passed to this invocation of the Special Sending Rule.
  • Value - The override hash (as defined above) with the settings to override.

See examples below.

Examples

We’ve created a practical set of examples for reference

Perl

Example Input to SSR

$campaign_information_hash = {
    seed_list_name    => 'GreenArrow Monitor',
    seed_list_id      => 12,
    seed_lists        => [ { id => 12, name => 'GreenArrow Monitor' } ],
    speed             => 0,
    from_name         => 'DRH Internet',
    from_email        => '[email protected]',
    sender_email      => undef,
    reply_to          => undef,
    virtual_mta_name  => 'smtp1-2',
    virtual_mta_id    => 3,
    url_domain_name   => 'http://newsletter.example.drh.net/',
    track_opens       => 1,
    track_links       => 1,
    bounce_email      => '[email protected]',
    campaign_name     => 'December newsletter',
    campaign_id       => 76,
    mailing_list_name => 'Newsletter subscribers',
    mailing_list_id   => 3,
};

$multiple_recipients_information_hash = {
    182634 => {
        subscriber => {
            id                       => 182634,
            email                    => '[email protected]',
            created_at               => '2014-12-03T08:39:53+12:00',
            created_at_epoch         => 1417595993,
            created_at_epoch_utc     => 1417552793,
            confirmed                => 1,
            email_format             => 'html',
            status                   => 'active'
            subscribe_time           => '2014-12-03T08:39:53+12:00',
            subscribe_time_epoch     => 1417595993,
            subscribe_time_epoch_utc => 1417552793,
            subscribe_ip             => '10.0.0.3',
            custom_fields            => {
                "First Name" => {
                    name  => "First Name",
                    type  => "text",
                    value => "Bob",
                },
                "Favorite Color" => {
                    name  => "Favorite Color",
                    type  => "select_single_dropdown",
                    value => "Red",
                },
            },
        },
        content => {
            format  => 'both',
            html    => '<html><body><p>Hello world</p><p><a href="%%unsubscribe_link%%">Unsubscribe me</a></p>/body></html>',
            text    => "Hello world\n\nUnsubscribe me: %%unsubscribe_link%%\n",
            subject => 'Hello',
        },
    },
};

Example Return Value

$return_value = {
    182634 => {
        html              => '<html><body><p>Hi there</p><p><a href="%%unsubscribe_link%%">Unsubscribe me</a></p>/body></html>',
        text              => "Hi there\n\nUnsubscribe me: %%unsubscribe_link%%\n",
        subject           => 'Hi',
        from_name         => 'DRH Internet Newsletter',
        from_email        => '[email protected]',
    },
};

Example Special Sending Rule that Passes Through the Values it Receives

## Available variables:
##
## $campaign_information_hash
## $multiple_recipients_information_hash
##
## NOTE: The example code below returns all potential values. For best
## performance, it's best to trim the return value down to just the fields
## you need to override.

my %result = map {
  my $recipient_id = $_;
  my $recipient    = $multiple_recipients_information_hash->{ $recipient_id };

  $recipient_id => {
    html              => $recipient->{content}{html},
    text              => $recipient->{content}{text},
    subject           => $recipient->{content}{subject},
    from_name         => $campaign_information_hash->{from_name},
    from_email        => $campaign_information_hash->{from_email},
    sender_email      => $campaign_information_hash->{sender_email},
    reply_to          => $campaign_information_hash->{reply_to},
    virtual_mta_name  => $campaign_information_hash->{virtual_mta_name},
    url_domain_name   => $campaign_information_hash->{url_domain_name},
    bounce_email      => $campaign_information_hash->{bounce_email},
  }
} keys(%$multiple_recipients_information_hash);

return \%result;

Example Special Sending Rule that Issues an HTTP GET to Replace the Text Content

use LWP::Simple;

my %result = map {
  my $recipient_id = $_;
  my $recipient    = $multiple_recipients_information_hash->{ $recipient_id };

  my $new_content = get("http://drh.net/robots.txt");

  $recipient_id => {
    text => $new_content,
  }
} keys(%$multiple_recipients_information_hash);

return \%result;

Example Special Sending Rule that Sends Using Different Virtual MTAs for Even and Odd Subscriber IDs

my %result = map {
  my $recipient_id = $_;
  my $recipient    = $multiple_recipients_information_hash->{ $recipient_id };

  my $override_hash = {};

  if ( $recipient_id % 2 == 0 ) {
    $override_hash->{virtual_mta_name} = "smtp-even";
  } else {
    $override_hash->{virtual_mta_name} = "smtp-odd";
  }

  $recipient_id => $override_hash;
} keys(%$multiple_recipients_information_hash);

return \%result;

PHP

Example Special Sending Rule that Passes Through the Values it Receives

## Available variables:
##
## $campaign_information_hash
## $multiple_recipients_information_hash
##
## NOTE: The example code below returns all potential values. For best
## performance, it's best to trim the return value down to just the fields
## you need to override.

return array_map((function ($recipient) use ($campaign_information_hash) {
  return array(
    'html'              => $recipient->content->html,
    'text'              => $recipient->content->text,
    'subject'           => $recipient->content->subject,
    'from_name'         => $campaign_information_hash->from_name,
    'from_email'        => $campaign_information_hash->from_email,
    'sender_email'      => $campaign_information_hash->sender_email,
    'reply_to'          => $campaign_information_hash->reply_to,
    'virtual_mta_name'  => $campaign_information_hash->virtual_mta_name,
    'url_domain_name'   => $campaign_information_hash->url_domain_name,
    'bounce_email'      => $campaign_information_hash->bounce_email,
  );
}), $multiple_recipients_information_hash);

Example Special Sending Rule that Issues an HTTP GET to Replace the Text Content

return array_map((function ($recipient) use ($campaign_information_hash) {
  $new_content = file_get_contents("http://drh.net/robots.txt");

  return array(
    'text' => $new_content,
  );
}), $multiple_recipients_information_hash);

Example Special Sending Rule that Sends Using Different Virtual MTAs for Even and Odd Subscriber IDs

return array_map((function ($recipient) use ($campaign_information_hash) {
  $override_hash = array();

  if ( $recipient->subscriber->id % 2 === 0 )
    $override_hash["virtual_mta_name"] = "smtp-even";
  else
    $override_hash["virtual_mta_name"] = "smtp-odd";

  return $override_hash;
}), $multiple_recipients_information_hash);