Home / Getting Started with ExactTarget Fuel

Getting Started with ExactTarget Fuel

8232 points
Michael Clark's picture

One of the most common uses of the ExactTarget Marketing Cloud is to send email. This tutorial walks you through the process of using ExactTarget Fuel to programmatically send an email to a list of subscribers. This example is designed to illustrate many of the basic concepts and techniques involved in using Fuel to programmatically send email both commercially and transactionally.

Basic Concepts

Before we get started, we need to introduce a few core Marketing Cloud concepts: subscribers, lists, profile attributes, and emails. These four concepts are the basis of any email communication that ties content, contacts, and subscription together.

Subscribers are contacts that have an email address and status. A subscriber can be active, held, or unsubscribed. If a subscriber is active, the Marketing Cloud can send email to that email address. If a subscriber is held, previous attempts to send email to that email address bounced. If a subscriber is unsubscribed, the Marketing Cloud will prevent email from being sent to that email address.

Lists contain subscribers and represent the simplest way to send email to multiple subscribers. Every account in the Marketing Cloud has an “All Subscribers” list that, as the name implies, contains all subscribers on all lists. All lists in an account are considered children of the “All Subscribers” list, so if a subscriber is unsubscribed on the “All Subscribers” list, they are considered unsubscribed on all lists, and the Marketing Cloud will not allow email to be sent to that subscriber. 

Profile attributes are arbitrary key/value pairs that can be associated with each subscriber. For example, you might use a profile attribute to store the subscriber’s first name so you can personalize email to the subscriber to refer to them by name (e.g., “Hi Dale”). Profile attributes exist at the “All Subscribers” list level and apply to all child lists that are created. You can create up to 200 profile attributes in an account.

Emails are delivered to lists of subscribers. An email is a template that can be personalized with substitution strings stored in your profile attributes. The email template governs how the email goes from being a skeleton of structure to a fully-rendered email capable of production sending against a production data source.

In this tutorial, we’ll show you how to use Fuel to programmatically create a profile attribute, create a list, add a subscriber to the list, create a personalized email, send the email to the list, and get back tracking events like opens and clicks. In the last section of the tutorial, we’ll show you how to personalize your email even further using advanced Marketing Cloud features like data extensions and AMPscript.

An overview of the objects used in the tutorial

Before you write any code, you'll want to read through an overview of ExactTarget Fuel and set up your development environment. Go ahead and do that if you haven't already done so.

Building an app

You’ll be using the PHP SDK to build your app, but all Fuel SDKs employ common patterns, so you’ll be able to adapt the example code to any of the other SDKs fairly easily. Install the PHP SDK in a subdirectory of your workspace called sdk. Make sure you have all dependencies installed as described in the SDK’s README.

Configuring the PHP SDK

To configure the SDK, you’ll need to add your OAuth credentials from App Center to config.php (the SDK contains a template file you can use to create config.php). Note that it is safe to include your OAuth credentials in config.php because config.php is hosted server side and not exposed to the client:

return array(
    'appsignature' => 'none', 
        'clientid' => 'YOUR_CLIENT_ID_FROM_APP_CENTER',
        'clientsecret' => 'YOUR_CLIENT_SECRET_FROM_APP_CENTER',
        'defaultwsdl' => 'https://webservice.exacttarget.com/etframework.wsdl'
);

Initializing the PHP SDK

After the SDK is configured, you initialize the SDK by instantiating an ET_Client object:

require('sdk/ET_Client.php');

$client = new ET_Client();

The ET_Client object is the central object in all Fuel SDKs and performs a number of tasks for you automatically, including acquiring and refreshing OAuth access tokens using the client credentials you specify in config.php.

Creating a profile attribute (a.k.a. defining your subscriber data model)

After initializing the SDK, you’ll create a profile attribute to hold the subscriber’s first name so you can personalize the email to that subscriber. Here’s how to create a profile attribute using the SDK:

$profileAttribute = new ET_ProfileAttribute();
$profileAttribute->authStub = $client;

$profileAttribute->props = array("Name" => "FirstName", "PropertyType" => "string", "Description" => "The subscriber's first name");

$response = $profileAttribute->post();

print_r($response);

This is a typical interaction with a Fuel SDK object and highlights the patterns common to all Fuel SDKs:

  1. Instantiate the object you want to interact with (in this case, ET_ProfileAttribute).
  2. Supply the ExactTarget account context via the authStub property on the object ($profileAttribute->authStub = $client).
  3. Set the appropriate properties that govern the operation (in this case, you are creating a profile attribute called FirstName which is a string and contains the subscriber’s first name).
  4. Perform a REST-like operation (get, post, patch, or delete) on the object depending on whether you want to retrieve, create, update, or delete it. In the example above, you are creating a profile attribute, so you perform a post.

When you load the PHP file in your browser, you should see something like this:

ET_Configure Object
(
    [status] => 1
    [code] => 200
    [message] => 
    [results] => Array
        (
            [0] => stdClass Object
                (
                    [StatusCode] => OK
                    [StatusMessage] => Success
                    [OrdinalID] => 0
                    [Object] => stdClass Object
                        (
                            [PartnerKey] => 
                            [ID] => 348977
                            [ObjectID] => 
                            [Name] => FirstName
                            [PropertyType] => string
                            [Description] => The subscriber's first name
                        )

                )

        )

    [request_id] => 
    [moreResults] => 
)

This is a typical response to a PHP SDK method invocation. For now, just note that the call (hopefully) succeeded, as indicated by StatusCode and StatusMessage.

Creating a list

After creating the profile attribute, you’ll create a list to hold your subscribers using the same pattern you used to create the profile attribute:

$list = new ET_List();
$list->authStub = $client;

$list->props = array("ListName" => "my subscribers");

$response = $list->post();

print_r($response);

Now when you load the PHP file in your browser, you should see something like this:

ET_Post Object
(
    [status] => 1
    [code] => 200
    [message] => 
    [results] => Array
        (
            [0] => stdClass Object
                (
                    [StatusCode] => OK
                    [StatusMessage] => Created List.
                    [OrdinalID] => 0
                    [NewID] => 1992264
                    [Object] => stdClass Object
                        (
                            [PartnerKey] => 
                            [ID] => 1992264
                            [ObjectID] => 
                            [ListName] => my subscribers
                        )

                )

        )

    [request_id] => 
    [moreResults] => 
)

This time, note the NewID property. When an object is created in the ExactTarget Marketing Cloud, a unique identifier is assigned to that object, and that unique identifier can be found in the response object’s NewID property. To refer to the object later, you can store its value in a variable like this:

$listID = $response->results[0]->NewID;

For now, just make note of what the value is. You’ll use that value in the next API call.

Adding a subscriber to the list

After creating a list, you’ll create a subscriber and add that subscriber to the list you just created. For the ID property, use the value of NewID from the previous example. For the EmailAddress property, use your email address. For the FirstName property, use your first name:

$subscriber = new ET_Subscriber();
$subscriber->authStub = $client;

$subscriber->props = array("EmailAddress" => "YOUR_EMAIL_ADDRESS_GOES_HERE", "Lists" => array("ID" => "YOUR_LIST_ID_GOES_HERE"));

$subscriber->props['Attributes'] = array(array('Name' => 'FirstName', 'Value' => 'YOUR_FIRST_NAME_GOES_HERE'));

$response = $subscriber->post();

print_r($response);

Go ahead and load the PHP file in your browser one more time.

Note: If your account is enabled with subscriber key, the previous code sample will not work unless you specify a SubscriberKey attribute in $subscriber->props.

Creating an email

After adding a subscriber to the list, you’ll create an email to send to the list:

$email = new ET_Email();
$email->authStub = $client;

$emailBody = <<<EMAIL
<html>
<body>

%%FirstName%%,

We're pretty sure you would love our products!

This email was sent by:

%%Member_Busname%%
%%Member_Addr%%
%%Member_City%%, %%Member_State%% %%Member_PostalCode%%
%%Member_Country%%

Profile Center

<custom name="opencounter" type="tracking">
</body>
</html>
EMAIL;

$email->props = array("Name" => "my email", "CustomerKey" => "123", "Subject" => "Hi %%FirstName%%, we think you will like this", "HTMLBody" => $emailBody, "IsHTMLPaste" => true);

$response = $email->post();

print_r($response);

This operation is much more complex than previous operations. Let’s use this call to highlight a few important concepts and features.

  • There’s a property called CustomerKey on the ET_Email object. This property is on every object in ExactTarget, and you can use it to attach your own identifier to an object. This makes it easier to integrate ExactTarget with your existing infrastructure.
  • A customer opening an email is an important touchpoint. To have ExactTarget track when customers open HTML email, we’ve added the following tag to the email body: <custom name="opencounter" type="tracking">
  • Both the email subject (the Subject property) and the email body (the HTMLBody property) contain substitution strings, denoted by %% on either side of the substitution string name. Some of these substitution strings are user-defined in profile attributes (like FirstName), and others are automatically resolved by ExactTarget.
  • There’s a property called IsHTMLPaste that’s set to true so users of the Marketing Cloud UI can only edit the content using the HTML editor. By default, and when IsHTMLPaste is set to false, the WYSIWYG editor will be the editing experience, but the content must provide templating hooks to be editable. If you’re doing an API-only integration, you do not need to specify this value.

Using substitution strings to personalize the email

User-defined substitution strings enable you to personalize your email to the recipient. A good email subject line is critical in creating a successful customer touchpoint, as a good subject line increases the chance that the recipient will open an email. Subject lines in ExactTarget can be personalized in a number of ways, including using substitution strings (e.g. “Thanks for your purchase, %%FirstName%%!”).

Once the recipient has opened your email, the content of the email will determine whether or not the recipient will engage (e.g., buy a product) or disengage (e.g., unsubscribe). In addition to substitution strings, ExactTarget provides many features to help you innovate and make your content more relevant, including the AMPscript content scripting language, HTTPGet content scraping, and sophisticated dynamic content functionality.

Substitution strings that are automatically resolved by ExactTarget make it easy for you to ensure that your content complies with CAN-SPAM laws for commercial sending. To help marketers comply with CAN-SPAM, ExactTarget requires every email to contain the following substitution strings:

%%Member_Busname%%
%%Member_Addr%%
%%Member_City%%
%%Member_State%%
%%Member_PostalCode%%
%%Member_Country%%

These substitution strings contain the elements of the sending organization’s physical address as required by CAN-SPAM and will be automatically filled in by ExactTarget based on the account information.

In addition, ExactTarget requires every email to contain a link to a profile center to manage subscription preferences, including whether the recipient of the email would like to opt out of future communications. ExactTarget builds and hosts these profile centers. To comply with CAN-SPAM, all you have to do is include the following substitution string:

%%profile_center_url%%

Sending the email

Now that you have created a list, added a subscriber to that list, and created an email to send to that list, you are ready to send your first email:

$response = new ET_Post($client, 'Send', array("List" => array("ID" => "YOUR_LIST_ID_GOES_HERE"), "Email" => array("CustomerKey" => "123")));

print_r($response);

Be sure to put the list ID you saved after you created the list where it says YOUR_LIST_ID_GOES_HERE.

Note that this example uses a slightly different SDK pattern—rather than calling a method on the email object, the code is calling an SDK method directly.

Reload the page again. As before, make note of the value of the NewID property—this is the unique identifier of the send we’ve just initiated, and it can be used to retrieve summary and raw individual statistics about the send, get the status of the send, pause it, restart it, or cancel it. You’ll be using it in the next section to get back a list of open events related to the send.

If all goes well, you should shortly receive an email that looks like this:

Your first ExactTarget email

Retrieving tracking event data

Retrieving tracking event data from ExactTarget is how you can measure the success of each of your customer touchpoints. ExactTarget captures a variety of tracking events for each send.

Delivery events related to the send enable you to know if your data is of good quality. These events are:

  • SentEvent, which indicates that the email was rendered and sent; and
  • BounceEvent, which indicates that the email bounced (was not delivered) either synchronously or asynchronously.

Engagement events related to the send enable you to know how a customer engaged with your email content:

  • OpenEvent, which indicates that the recipient opened the email (note: this only works for HTML emails that include the tracking pixel above and after the recipient allows images to be loaded).
  • ClickEvent, which indicates that the recipient clicked on a link in the email (this only works if ExactTarget wraps the links).
  • UnsubEvent, which indicates that the recipient unsubscribed from the list either by spam complaint, reply mail management (responded to the email saying “please remove me”), or the profile center.

In this example, you get all of the OpenEvents for the send you just performed and print them to the browser window or console:

$openEvent = new ET_OpenEvent();
$openEvent->authStub = $client;

$openEvent->props = array("SubscriberKey", "EventType", "EventDate");

$openEvent->filter = array("Property" => "SendID", "SimpleOperator" => "equals", "Value" => array(YOUR_SEND_ID_GOES_HERE));

$response = $openEvent->get();

print_r($response);

Again, be sure to put the send ID you saved after you performed the send where it says YOUR_SEND_ID_GOES_HERE.

Now when you load the PHP file in your browser, you should see something like this:

ET_Get Object
(
    [status] => 1
    [code] => 200
    [message] => 
    [results] => Array
        (
            [0] => stdClass Object
                (
                    [PartnerKey] => 
                    [ObjectID] => 
                    [SubscriberKey] => jflathead@example.com
                    [EventDate] => 2013-11-09T19:01:33
                    [EventType] => Open
                )

        )

    [request_id] => 6816994f-125b-4932-9003-bc669c1ea7cc
    [moreResults] => 
)

This shows that the subscriber with the subscriber key jflathead@example.com opened the email on November 9, 2013 at 7:01pm. Subsequent calls will only return open events since the last call.

Using the API directly

If you are using a language or platform where the SDKs are not available or are otherwise not a viable solution, you can use the API directly rather than going through the SDK.

Getting an access token

The first step in any API-based integration is getting an access token, which will be used to authenticate other API calls. To get an access token, you will use Fuel’s authentication service. The code sample below demonstrates how to use an HTTP POST request to acquire an access token:

POST https://auth.exacttargetapis.com/v1/requestToken
Content-Type: application/json
{
    "clientId": "YOUR_CLIENT_ID_FROM_APP_CENTER",
    "clientSecret": "YOUR_CLIENT_SECRET_FROM_APP_CENTER"
}

200 OK
{
    "accessToken": "dfy3dsnqw3gre6e3pbatcr4s"
    "expiresIn": 3600
}

The access token is returned in the accessToken property. You can use this token to authenticate other API calls by either specifying it via the query string parameter access_token or via the Authorization header field with the Bearer HTTP authorization scheme, e.g.,

GET https://www.exacttargetapis.com/platform/v1/endpoints?access_token=dfy3dsnqw3gre6e3pbatcr4s
Accept: application/json

or

GET https://www.exacttargetapis.com/platform/v1/endpoints
Accept: application/json
Authorization: Bearer dfy3dsnqw3gre6e3pbatcr4s

Fuel access tokens can be used to authenticate with ExactTarget’s SOAP API as well. Here is an example of using the same access token to authenticate with the SOAP API:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:fueloauth xmlns="http://exacttarget.com"
                 xmlns:h="http://exacttarget.com">
      dfy3dsnqw3gre6e3pbatcr4s
    </h:fueloauth>
  </s:Header>
  [...]
</s:Envelope>

Refreshing an access token

Note the expiresIn property in the HTTP response to the requestToken API call. Fuel access tokens expire one hour after they are issued. If you attempt to use an expired token, you will receive a 401 Unauthorized HTTP response. If this happens, you will need to refresh your access token.

Important considerations when using the API directly

There are two important considerations to keep in mind if you use the API directly and do your own OAuth token management rather than using the SDKs.

First of all, you should NOT request a new token for every API call you make—each token is good for an hour and should be reused. Making two API calls for every one operation is inefficient and may result in throttling.

Secondly, and we cannot say this enough, be careful where you store your client secret. In particular, you should NOT store your client secret in a mobile application because a mobile device is not a secure environment; it is recommended that you utilize an Authorization Code or Implicit Grant OAuth flow instead.

Using Data Extensions and AMPscript for Advanced Personalization

In this section, we’ll make our message even more personalized and relevant through the use of two advanced Marketing Cloud technologies: data extensions and AMPscript.

A data extension is a flexible table of almost any type of data and can be used for personalization, segmentation, or as a sending data source. Data extensions are very powerful constructs and can be thought of as cloud-based, relational marketing databases.

AMPscript is the Marketing Cloud’s content scripting language and can be used to programmatically personalize the content of an email, SMS message, or landing page. AMPscript can interact with data extensions, so you can read data from data extensions in your messages and write data to your data extensions in your landing pages.

In our example below, we will use a data extension to store information about products that we can use to further personalize the email we sent in the last section. Specifically, we will use the subscriber’s previous purchase behavior to include a relevant offer in our email designed to drive the next purchase.

Creating a data extension

First, you will create a data extension called Products to store your product catalog. In our example, each product will have a unique identifier, a name, a price, and an image URL:

idnamepriceimage
............

Let’s go ahead and create the data extension using the SDK:

$de = new ET_DataExtension();
$de->authStub = $client;

$de->props = array("Name" => "Products", "CustomerKey" => "products");

// specify the data extension columns
$de->columns = array();
$de->columns[] = array("Name" => "id", "FieldType" => "Number", "IsPrimaryKey" => "true", "IsRequired" => "true");
$de->columns[] = array("Name" => "name", "FieldType" => "Text", "MaxLength" => "100");
$de->columns[] = array("Name" => "price", "FieldType" => "Decimal", "Precision" => "18", "Scale" => "2");
$de->columns[] = array("Name" => "image", "FieldType" => "Text", "MaxLength" => "100");

$response = $de->post();

print_r($response);

Populating the data extension

After creating the Products data extension, you will add some product data to it. In essence, you will be adding two new rows to the Products database:

idnamepriceimage
1234iPhone 5c99.95http://bit.ly/H76rMz
5678iPhone 5c case29.95http://bit.ly/Hesctp

Let’s go ahead and create the two new rows:

$deRow = new ET_DataExtension_Row();
$deRow->authStub = $client;

// specify the name of the data extension
$deRow->Name = "Products";	

// specify the values of data extension row #1
$deRow->props = array("id" => "1234", "name" => "iPhone 5c", "price" => "99.95", "image" => "http://bit.ly/H76rMz");

$response = $deRow->post();

print_r($response);

// specify the values of data extension row #2
$deRow->props = array("id" => "5678", "name" => "iPhone 5c case", "price" => "29.95", "image" => "http://bit.ly/Hesctp");

$response = $deRow->post();

print_r($response);

The approach above is ideal for small- to medium-sized data sets like real-time or near real-time updates to single rows or small batches of data in periodic updates. For example, if you want to send ExactTarget purchase data as it happens or on a frequent basis (say hourly), utilizing the API approach is ideal.

Other scenarios require bulk loading of data into a data extension. For example, if you want to load millions of products into ExactTarget regularly, a file based approach may be more efficient from a bandwidth and processing standpoint. Importing compressed files dropped onto an FTP site is the most efficient way to bulk load millions of rows of data into a data extension.

Extending the subscriber data model

After populating the data extension, you will create another profile attribute, this time to store the ID of the product to recommend next:

$profileAttribute = new ET_ProfileAttribute();
$profileAttribute->authStub = $client;

$profileAttribute->props = array("Name" => "productID", "PropertyType" => "double", "Description" => "ID of next product recommendation");

$response = $profileAttribute->post();

print_r($response);

In a real world use case, a background process might be running that analyzes past purchases and populates the productID profile attribute with the product it determines is most relevant to include next for each subscriber. In our case, we’ll need to populate the productID profile attribute manually. Go ahead and set it to 5678.

Using AMPScript to bring it all together

Finally, you will update the email to include AMPscript that uses the profile attribute productID to read details about that product from the Products data extension and include those details in the email message. Note that this time you use patch because you are updating an existing email:

$email = new ET_Email();
$email->authStub = $client;

$emailBody = <<<EMAIL
<html>
<body>

%%FirstName%%,

We're pretty sure you would love the following product:

%%=Lookup("Products", "name", "id", productID)=%%
$%%=Lookup("Products", "price", "id", productID)=%%

We appreciate your continued business!

This email was sent by:

%%Member_Busname%%
%%Member_Addr%%
%%Member_City%%, %%Member_State%% %%Member_PostalCode%%
%%Member_Country%%

Profile Center

<custom name="opencounter" type="tracking">
</body>
</html>
EMAIL;

$email->props = array("CustomerKey" => "123", "Subject" => "Hi %%FirstName%%, may we suggest for your next purchase...", "HTMLBody" => $emailBody);

$response = $email->patch();

print_r($response);

$response = new ET_Post($client, 'Send', array("List" => array("ID" => "YOUR_LIST_ID_GOES_HERE"), "Email" => array("CustomerKey" => "123")));

print_r($response);

The AMPScript used in the email above is the Lookup function. The Lookup function returns a single field value for a single row in a data extension. For example, in our case, the AMPscript

%%=Lookup("Products", "price", "id", productId)=%%

outputs

29.95

In this example, you are looking up the value of the price field from the Products data extension. The Products data extension has one primary key, and the final two parameters of the Lookup function provide the name and value of that primary key. In our case, the value of this key is the product ID data specified in the subscriber’s profile attribute productID.

If all goes well, you should shortly receive an email that looks like this:

Your first ExactTarget email, even more personalized and relevant

Now It’s Your Turn

You have completed building a relatively sophisticated email communication using a number of ExactTarget technologies and concepts. This exercise hopefully has you thinking of creative ways to use your organization’s data to create more personalized and beneficial customer touchpoints.