This article explains how to use WSProxy for working with subscriber Lists in server-side JavaScript in Salesforce Marketing Cloud.
Table of contents
Lists, what are they?
Lists are the default method of storing subscriber’s data in the Email Studio.
In short, it’s a convenient out-of-the-box solution for the audience segmentation with a rather simple data model and a limited Subscriber count (500k).
There are 2 types of Email Studio lists: Publication list and Suppression list.
Publication lists control which emails your subscribers receive and the Suppression lists prevent your subscribers from receiving specific communications.
But there is also a third type of list that can be found in the Email Studio Admin panel: Auto-suppression list.
In a nutshell, they are similar to the regular Suppressions lists but work across an entire Marketing Cloud business unit for specific send classifications.
Now, let’s see how work with these different types of lists, using WSProxy in server-side JavaScript.
Before we start
Please consider that the examples of code presented in the next sections will need to be implemented in the following basic template:
<script runat="server">
Platform.Load("core", "1");
var api = new Script.Util.WSProxy();
try {
/////////////////////////////////////////////////
///// PASTE CODE HERE
/////////////////////////////////////////////////
Write(Stringify(res));
} catch(error) {
Write(Stringify(error));
}
</script>
Basics
Create a List
Creating a new List is nice and easy when using WSProxy with the List API object.
var res = api.createItem("List", {
ListName: "My NewList",
Type: "Public",
ListClassification: "PublicationList",
Description: "Hello world"
});
Please note that the name attribute of the List is called ListName instead of the usual Name.
Type and ListClassification attributes each have a valid set of values:
Type attribute can only be equal to:
- Public
- Private
- Salesforce
- GlobalUnsubscribe
- Master
As for the ListClassification attribute, it accepts exclusively the following values:
- ExactTargetList
- PublicationList
- SuppressionList
Delete a List
Deleting a list is a matter of providing the List ID, which can be found in Email Studio UI, but the column is hidden by default, so please activate it.
var res = api.deleteItem("List", {
ID: "12345"
});
Retrieve a List
In order to retrieve a List, we need to use the complex filters.
var res = api.retrieve("ListSubscriber",
["SubscriberKey", "ListID", "Status"],
{
Property: "SubscriberKey",
SimpleOperator: "equals",
Value: "0x000000012345"
}
);
Folders
Retrieve the folder
In the example below, we first need to fetch the Category ID of the List (called Category, instead of the usual CategoryId) and then use it to retrieve the name of the folder where the List is located.
var req = api.retrieve("List", ["ListName", "Category", "ID"], {
Property: "ID",
SimpleOperator: "equals",
Value: "12345"
});
var catId = req.Results[0].Category;
var req = api.retrieve("DataFolder", ["Name"], {
Property: "ID",
SimpleOperator: "equals",
Value: catId
});
var res = req.Results[0].Name;
Retrieve the folder path
Same here, but in order to retrieve the full path, we need to fetch the ID of the Parent Folder and then loop the process until the Parent Folder ID is equal to 0 (root level folder).
var req = api.retrieve("List", ["ListName", "Category", "ID"], {
Property: "ID",
SimpleOperator: "equals",
Value: "12345"
});
var list = [req.Results[0].ListName];
var id = req.Results[0].Category;
while(id > 0) {
var req = api.retrieve("DataFolder", ["Name","ParentFolder.ID"], {
Property: "ID",
SimpleOperator: "equals",
Value: id
});
list.unshift(req.Results[0].Name);
id = req.Results[0].ParentFolder.ID;
}
var res = list.join(" / ");
Managing subscribers
Add a subscriber to a List
The method of adding a new subscriber is a matter of updating or adding a new Subscriber API object and providing one or multiple List IDs to which the subscriber needs to be added.
/*
Statuses: Active, Bounced, Held, Unsubscribed, Deleted
*/
var res = api.updateItem("Subscriber", {
SubscriberKey: "0x000000012345",
EmailAddress: "jon.snow@crowmail.com",
Status: "Active",
EmailTypePreference: "HTML",
Attributes: [
{
Name: "FirstName",
Value: "Jon"
},
{
Name: "LastName",
Value: "Snow"
}
],
Lists: [
{
ID: "12345"
}
]
},
{
SaveOptions: [
{
PropertyName: '*',
SaveAction: 'UpdateAdd'
}
]
});
Note that each of the specific subscriber’s attribute needs to be provided as a separate object with a Name/Value pair.
Status and EmailTypePreference attributes each have a list of valid values.
Status only accepts the following values:
- Active
- Bounced
- Held
- Unsubscribed
- Deleted
EmailTypePreference on the other hand can only accept:
- HTML
- Text
Change subscriber’s status in a List
Changing the status of the subscriber is done in the same manner.
/*
Statuses: Active, Bounced, Held, Unsubscribed, Deleted
*/
var res = api.updateItem("Subscriber", {
SubscriberKey: "0x000000012345",
EmailAddress: "jon.snow@crowmail.com",
Status: "Unsubscribed",
Lists: [
{
ID: "12345"
}
]
},
{
SaveOptions: [
{
PropertyName: '*',
SaveAction: 'UpdateAdd'
}
]
});
Retrieve all subscribers from a List
Retrieving all the subscribers from a List if a matter of querying the ListSubscriber object.
var res = api.retrieve("ListSubscriber",
[
"ObjectID",
"SubscriberKey",
"CreatedDate",
"ModifiedDate",
"Client.ID",
"Client.PartnerClientKey",
"ListID",
"Status"
],
{
Property: "ListID",
SimpleOperator: "equals",
Value: "12345"
}
);
Remove a subscriber from a Suppression List
For some reason, the List ID of a Suppression List cannot be found in the Email Studio UI. We therefore need to retrieve the List ID based on the name of the List and only then update the Subscriber object’s Lists array.
var req = api.retrieve("List",
["ListName", "ID"],
{
Property: "ListName",
SimpleOperator: "equals",
Value: "My New Suppression List"
}
);
var listId = req.Results[0].ID;
var res = api.updateItem("Subscriber", {
SubscriberKey: "0x000000012345",
EmailAddress: "jon.snow@crowmail.com",
Lists: [
{
ID: listId,
Action: "delete"
}
]
});
Note that removing a subscriber from a regular or Publication List is not possible with code. The subscriber remains in the List with the status Unsubscribed.
Interacting with Auto-Suppression Lists
Create an Auto-Suppression List for a Send Classification
In order to create a proper Auto-Suppression List, we need to provide the Client ID in the Contexts array attribute, which is a fancy name for a Business Unit number (or mid).
var res = api.createItem("SuppressionListDefinition", {
Name: "My New Sup List Def",
Category: 0,
Description: "Hello world",
Contexts: [
{
Client: {
ID: Platform.Recipient.GetAttributeValue("memberid")
},
Context: "BusinessUnit",
SendClassificationType: "Marketing",
AppliesToAllSends: false
}
]
});
Create an Auto-Suppression List for a Sender Profile
Same here, but we also need to provide the ObjectID of the Sender Profile we count on using.
var req = api.retrieve("SenderProfile", ["Name", "ObjectID"], {
Property: "CustomerKey",
SimpleOperator: "equals",
Value: "1134"
});
var objId = req.Results[0].ObjectID;
var res = api.createItem("SuppressionListDefinition", {
Name: "My New Sup List Def 2",
Category: 0,
Description: "Hello world",
Contexts: [
{
Client: {
ID: Platform.Recipient.GetAttributeValue("memberid")
},
Context: "SenderProfile",
SenderProfile: {
ObjectID: objId
},
AppliesToAllSends: false
}
]
});
Add a subscriber to an Auto-Suppression List
Adding a new subscriber is done differently for an Auto-Suppression List. The method is the same as adding a new record in a Data Extension.
var req = api.retrieve("SuppressionListDefinition",
[
"ObjectID",
"CustomerKey",
"Name",
"Description",
"Client.CreatedBy",
"CreatedDate",
"Client.ModifiedBy",
"ModifiedDate",
"Category",
"Client.ID",
"Client.EnterpriseID",
"SubscriberCount"
],
{
Property: "Name",
SimpleOperator: "equals",
Value: "My New Sup List Def "
}
);
var customerKey = req.Results[0].CustomerKey;
var res = api.updateItem("DataExtensionObject", {
CustomerKey: customerKey,
Properties: [
{
Name: "Email Address",
Value: "jon.snow@crowmail.com"
}
]
},
{
SaveOptions: [
{
PropertyName: '*',
SaveAction: 'UpdateAdd'
}
]
});
Retrieve all Auto-Suppression Lists
An Auto-Suppression List is basically a SuppressionListDefinition object and has the same structure as a regular Data Extension, except for the SubscriberCount attribute.
var res = api.retrieve("SuppressionListDefinition",
[
"ObjectID",
"CustomerKey",
"Name",
"Description",
"Client.CreatedBy",
"CreatedDate",
"Client.ModifiedBy",
"ModifiedDate",
"Category",
"Client.ID",
"Client.EnterpriseID",
"SubscriberCount"
]
);
Retrieve Contexts for an Auto-Suppression List
The SuppressionListContext object defines a context that an Auto-Suppression List can be associated with.
var res = api.retrieve("SuppressionListContext",
[
"ObjectID",
"Definition.ObjectID",
"Definition.Name",
"Definition.CustomerKey",
"Definition.Category",
"Definition.Description",
"Context",
"SendClassification.ObjectID",
"Send.ID",
"SenderProfile.ObjectID",
"SendClassificationType",
"Client.CreatedBy",
"CreatedDate",
"Client.ModifiedBy",
"ModifiedDate",
"Client.ID",
"Client.EnterpriseID",
"AppliesToAllSends"
]
);
Conclusion
Lists are far from a perfect system but knowing how to manage them with code can be a powerful tool in our Marketing Cloud projects.
Have I missed anything?
Please poke me with a sharp comment below or use the contact form.
Hi, Ivan, first of all, congratulations on the content,
I would like to know if it’s possible to move data from a data extension to a suppression list using SSJS?
Thanks you very much
Of course you can, here is what you’ll need to know:
https://ampscript.xyz/how-tos/how-to-retrieve-more-than-2500-records-from-a-data-extension-with-server-side-javascript/
https://ampscript.xyz/how-tos/how-to-process-data-extension-records-in-a-script-activity-using-server-side-javascript/
Hi, Ivan, I would like to know how could I move data from a list to a Data Extension using SSJS, it’s possible? Thanks Ivan
Sure, why not. Just keep in mind that you are going to be able to process around 100-150k records at a time, since Script Activities have a 30 min time-out period.
Hi Ivan, can I retrieve more than just 2500 subscribers from a list? When I see my recovered subscribers on the web page, it appears for me
“HasMoreRows”:true, how can I retrieve all subscribers at once? Thanks in advance
Sure thing, apply the technique I describe on this page: https://ampscript.xyz/how-tos/how-to-retrieve-more-than-2500-records-from-a-data-extension-with-server-side-javascript/
Alright! I’m trying to recover a list so when you say here,
” if (reqID == null) {
data = prox.retrieve(“DataExtensionObject[” + config.name + “]”, config.cols, config.filter);
} else {
data = prox.getNextBatch(“DataExtensionObject[” + config.name + “]”, reqID);
}”
In the place of “DataExtensionObject[” what should I put?
You can read it above in this article under the title « Retrieve a List ».
If you still can’t put 2 and 2 together, don’t try to make it work without having a proper JavaScript training. If you don’t know the basics, you’ll have a really hard time understanding any of this.
Hi Ivan! Thank you for this! I have a question. How i could remove all subscribers from a Suppression List?
thank you in advance !
Hi! You’ll need to retrieve all subscribers first (use this page as reference: https://ampscript.xyz/how-tos/how-to-retrieve-more-than-2500-records-from-a-data-extension-with-server-side-javascript) and perform the delete action with a updateBatch function (https://developer.salesforce.com/docs/atlas.en-us.noversion.mc-programmatic-content.meta/mc-programmatic-content/ssjs_WSProxy_create.htm).
Thanks Ivan,
I am looking for to get a subscriber from a particular list and then checking the status.
I can see above there is an option to retrieve all the subscriber from the list but not a particular subscriber from the list. IS there any way we can get the particular subscriber from the list with status.
Of course! Just put SubscriberKey instead of ListID and provide a corresponding value.
Hi Evan – Thanks for the document. This helps a lot. I have a question on how to unsubsciber user from a child to child BU? I don’t want to do this from parent BU. I am trying to unsub the user from all subs from child to child BU. Say host the unsub page in child BU1 and only want this user to unsub from Child BU2 only (not child BU1).
I’m afraid we can only modify child BUs from a Parent BU 🙁