CRM systems generally have the ability to define campaigns. Leads and contacts are added to a campaign – sometimes indirectly via marketing lists or dynamically via machine-learning algorithms – and campaign activities are subsequently defined and executed. Using the closed-loop service, you can transfer members of a campaign to Optimizely Campaign. With additional meta-information (Client ID and/or opt-in ID and mailing ID), the appropriate mailing is triggered in Optimizely Campaign. Events that follow the campaign, such as openings, clicks, bounces or unsubscriptions, are then made available to the CRM system. See Closed-loop Interface.
Personalizing and formatting a recipient
Contact customer support to help you define the recipient list format - the columns containing information transferred to Optimizely Campaign.
The recipient list must contain the desired personalization information. For example, to use recommendations from CRM, place the product information in the recipient list. To use a personalized greeting and/or complimentary close (so the contact’s sales owner appears as point of contact in the salutation), transfer the corresponding sales owner fields.
You can also add recipient list fields to response data, making it easier to assign events in CRM, such as open or click. For example, providing two fields in the recipient list for identifier of entities, these can be transferred back in the response data.
Example: A contact has a unique ID <contact-id> and each campaign has a unique identifier <campaign-id>. Both fields are added to the recipient list, and the entities are transferred to Optimizely Campaign. When clicking the link in the sent email, the recipient receives the result with the corresponding <contact-id> and <campaign-id>, so you can assign events to a contact or a campaign response.
The displayed fields depend on the CRM system. Typical identification fields may be <contact-id>, <lead-id>, <campaign-id>, <campaign-member-id>, <member-id> or <list-id>.
Protocols and feedback
You can use either SFTP or SOAP protocols for data transfer. SOAP transfers the data via XML; you have better performance with sending CSV files via SFTP, especially for large campaigns with several hundred thousand campaign members.
When a campaign is sent, Optimizely Campaign can create feedback messages such as an email notification. Optimizely Campaign can also call up SOAP services and systemically display the processing and send status.
Process sequence
After the CSV file is delivered or data transfer is completed through the SOAP service, no further action is required on the part of the CRM or the requesting party. The following process automatically takes place in Optimizely Campaign:
- After successful transfer, the recipient data is automatically loaded into a recipient list. The recipient lists used for this purpose are subject to a check by the closed-loop services and have the Z_CampaignUserList prefix. Lists with this prefix are automatically created and managed. These special lists may not be used for other purposes – neither through interfaces nor through Optimizely Campaign’s front-end. These lists may not be used, filled nor otherwise addressed using an Optimizely Campaign API method.
- After the recipient data is fully imported, the specified mailing will automatically be copied. If you start a campaign from the CRM system via the closed-loop service, you will also find a sent mailing in the mailing overview.
- After the mailing is sent, results are recorded, prepared and made available. These include opens, clicks, bounces and unsubscriptions. Bounces and unsubscriptions are directly linked to an email address and should be saved at the appropriate entities in CRM. For instance, there is no point in continuing to send messages to an email address that has bounced out. If someone unsubscribes, then this must be saved in the appropriate contact and/or lead and, if necessary, in an advertising consent.
Recipient lists match database tables. These are generally generated individually according to your requirements in a format specified by customer support. This format is static and may not be changed without consulting customer support.
broadmail_ID parameter
The broadmail_ID denotes a mailing. The advertising channel (email, print, SMS) also appears on the mailing. Therefore, the broadmail_ID can also be used to trace back the medium. In addition to the mandatory broadmail_ID, the CRM system can also issue a numerical wave-ID for a mailing, with which the mailing wave is identified. If a mailing is sent in multiple steps, then the mailing identity can be inferred using the wave_ID. The broadmail_ID and the wave_ID must be unique Grouping different mailings into one mailing wave is not possible. Furthermore, the recipient’s email address is a mandatory field in the recipient list.
Example: The following code block shows an implementation example of how a campaign with two recipients can be started by Optimizely Campaign using SOAP services. The surrounding category provides the necessary member variables, for instance, the closedLoopWebservice object makes available the methods documented in the SOAP API.
/** * Use case: Initialise and start campaign * The following class is an implementation on how to start a campaign * via Closed Loop Webservice. */private class ImportRecipientsAndStartCampaign extends UseCase { @Override void runExceptional() throws Exception { // create a waveId, fix the template mailing _waveId = _closedLoopWebservice.prepareNewWave( _session.getSessionId(), TEMPLATE_CAMPAIGN_ID); // The recipient field names can be different for every client // and are defined once during the configuration process in // optivo broadmail. Within the example code we used // recipientFieldNames are for demo purposes with most common // used fields. String[] recipientFieldNames = { "salutation" , "firstname" , "lastname" , "title" , "birthday" , "mobile" , "email" , "street" , "zipcode" , "city" , "state" , "country" , "extentityid" , "extcampaignid"}; String[][] recipientFieldValues = { { "Mr." , "John" , "Doe" , "Phd" , "17.2.1956" , "0049307680780" , "it-demo-mr@example.com" , "Wallstrasse 16" , "10179" , "Berlin" , "Berlin" , "Germany" , "SAP-321XWZ654987" , "SAP-987ABG654223" } , { "Mrs." , "Jane" , "Doe" , "Phd" , "17.2.1952" , "0049307680780" , "004930768078199" , "it-demo-mrs@example.com" , "Wallstrasse 16" , "10179" , "Berlin" , "Berlin" , "Germany" , "SAP-321XWZ654988" , "SAP-987ABG654223" } }; _closedLoopWebservice.importRecipients( _session.getSessionId() , _waveId , recipientFieldNames , recipientFieldValues); // initialise the point in time the campaign will start to // generate response data _since = _closedLoopWebservice.getCurrentTime( _session.getSessionId()); _closedLoopWebservice.importFinishedAndScheduleMailing( _session.getSessionId(), _waveId); }}
You can request the mailing status after transferring a campaign. The following category shows the methods that need to be invoked.
/** * Use case: Receive campaign status. * Use this code to ask campaign status from optivo broadmail. This * makes sense after calling the use case "Initialise and start campaign" */private class DetermineCampaignStatus extends UseCase { @Override void runExceptional() throws Exception { if (_waveId <= 0) { throw new IllegalStateException("waveId not positive."); } // Since the campaign is copied before it is started, we // have to translate the wave id to the campaign id that // was actually sent ... long campaignId; do { campaignId = _closedLoopWebservice.getMailingIdByWaveId( _session.getSessionId(), _waveId); if (campaignId <= 0) { sleepOneMinute(); } } while (campaignId <= 0); // customise this to your needs. After a campaign switched to // status SENT, the status will be immutable while (true) { String campaignStatus = _mailingWebservice.getStatus( _session.getSessionId(), campaignId); if ("DONE".equals(campaignStatus)) { break; } if ("PAUSED".equals(campaignStatus) || "CANCELED".equals( campaignStatus)) { throw new RuntimeException( "Campaign is " + campaignStatus); } String campaignName = _mailingWebservice.getName( _session.getSessionId(), campaignId); // Log status for messages of campaign too. long[] messageIds = _splitMailingWebservice.getSplitChildIds( _session.getSessionId(), campaignId); for (long messageId : messageIds) { String messageStatus = _mailingWebservice.getStatus( _session.getSessionId(), campaignId); String messageName = _mailingWebservice.getName( _session.getSessionId(), messageId); } sleepOneMinute(); } } private void sleepOneMinute() throws InterruptedException { Thread.sleep(TimeUnit.MINUTES.toMillis(1)); }}
You can also show your campaign manager the available templates. The following example shows a query for the Smart Campaigns.
/** * Use case: Read available campaigns for closed loop scenario * This is a usability method. You can show available Smart Campaigns * to your campaign manager. Scenario for smart campaigns only. */private class GetCampaignData extends UseCase { @Override void runExceptional() throws Exception { String campaignType = "regular"; String campaignStatus = "ACTIVATION_REQUIRED"; long[] campaignIds = _mailingWebservice.getIdsInStatus( _session.getSessionId(), campaignType, campaignStatus); for (long campaignId : campaignIds) { String campaignName = _mailingWebservice.getName( _session.getSessionId(), campaignId); String description = _mailingWebservice.getDescription( _session.getSessionId(), campaignId); long[] messageIds = _splitMailingWebservice.getSplitChildIds( _session.getSessionId(), campaignId); for (long messageId : messageIds) { String messageName = _mailingWebservice.getName( _session.getSessionId(), messageId); String messageDescription = _mailingWebservice.getDescription( _session.getSessionId(), messageId); } } }}
Processing response data
Response data processing must be implemented when a campaign is being executed. Bounces, unsubscriptions and replies are part of these processes. You have the choice of using Optimizely Campaign’s features for managing unsubscriptions or implementing proprietary processes in CRM. Processing unsubscriptions and replies is mandatory due to applicable rules on advertising consents and competition law.
Unsubscribing via Optimizely Campaign
An unsubscribe link must be included in every email. If the link points to Optimizely Campaign, the recipient is added to the unsubscribed list in Optimizely Campaign, and receives no more email. The unsubscribed list in Optimizely Campaign has precedence over additional mailings. This means that recipients do not receive emails even if they are included in a CRM selection which is transferred to Optimizely Campaign. The unsubscription can only be revoked using a new double opt-in process.
If the recipient has unsubscribed using the Optimizely Campaign processes, the unsubscription is sent back to the CRM using the closed-loop interface. The CRM system must process the unsubscriptions obtained in this manner and save them in applicable entities. The transferred selections may not contain any recipients that have effectively revoked their advertising consent.
If an unsubscription is performed via another method, such as through the customer center in a shop system, then these unsubscriptions do not necessarily have to be sent to Optimizely Campaign, provided that the unsubscriptions are actively saved in the referentially-leading system. In any case, it must be ensured that active unsubscriptions are not included in selections and campaigns sent to Optimizely Campaign.
Unsubscribing via third-party systems
If you use your own unsubscription links, Optimizely Campaign will not receive any information about unsubscriptions. Forwarding is not possible. In this case, the systemic responsibility for properly using advertising consents lies fully with CRM.
Reply emails
Recipients can answer emails and express additional requests such as an unsubscription. Either of these returned emails are processed in the Optimizely Campaign’s user interface, or forwarded to the inbox of your choice, as configured in Optimizely Campaign.
Data formats
Each field in the recipient list can be filled via the closed-loop interface or HTTP API. The data format in the transferred files can be mapped to fields in the recipient list, irrespective of the set-up of the closed-loop interface. Therefore, the format of the recipient list does not necessarily match the one that the closed-loop interface expects. Contact customer support for exact data formats.
Conversely, the HTTP API can directly fill fields in the recipient list. The names of the HTTP parameters here must directly match the ones stated in the recipient list. See HTTP API.
Event emails
Event emails are typically triggered by a certain event. For instance, this can be a registration, or an order placement or cancellation. This type of email can ideally be sent over the HTTP API. Here, you can save a decided recipient list suitable for sending these special mailings. You can link as many mailings as you want to this recipient list and send result-based emails individually. This type of integration is also suitable for Marketing Automation campaigns triggered based on events and points in time.
Implementation example
The following code block shows an example of how response data can be retrieved.
/** * Use case: Get response data * This use case shows how to receive and process reponse data. * Response data are fetched within a certain interval, usually * 1-4 h, and processed according to your system needs.*/private class GetResponseData extends UseCase { @Override void runExceptional() throws Exception { long until = _closedLoopWebservice.getCurrentTime( _session.getSessionId()); int numberOfRows = 1000; int startRow = 0; String[][] recipients; do { recipients = _closedLoopWebservice.getRecipients( _session.getSessionId(), _since, until, startRow, numberOfRows); processData(recipients); startRow += numberOfRows; } while (recipients.length >= numberOfRows); startRow = 0; String[][] clicks; do { clicks = _closedLoopWebservice.getClicks( _session.getSessionId(), _since, until, startRow, numberOfRows); processData(clicks); startRow += numberOfRows; } while (clicks.length >= numberOfRows); startRow = 0; String[][] opens; do { opens = _closedLoopWebservice.getOpens( _session.getSessionId(), _since, until, startRow, numberOfRows); processData(opens); startRow += numberOfRows; } while (opens.length >= numberOfRows); startRow = 0; String[][] links; do { links = _closedLoopWebservice.getLinks( _session.getSessionId(), _since, until, startRow, numberOfRows); processData(links); startRow += numberOfRows; } while (links.length >= numberOfRows); startRow = 0; String[][] responses; do { responses = _closedLoopWebservice.getResponses( _session.getSessionId(), _since, until, startRow, numberOfRows); processData(responses); startRow += numberOfRows; } while (responses.length >= numberOfRows); startRow = 0; String[][] unsubscribes; do { unsubscribes = _closedLoopWebservice.getUnsubscribes( _session.getSessionId(), _since, until, startRow, numberOfRows); processData(unsubscribes); startRow += numberOfRows; } while (unsubscribes.length >= numberOfRows); startRow = 0; String[][] mailingUnsubscribes; do { mailingUnsubscribes = _closedLoopWebservice.getMailingUnsubscribes( _session.getSessionId(), _since, until, startRow, numberOfRows); processData(mailingUnsubscribes); startRow += numberOfRows; } while (mailingUnsubscribes.length >= numberOfRows); _since = until; } // customize this method according to your needs. This // includes creating campign reactions or upsert subscription- // or bounce status to your entities. private void processData(String[][] values) { if (values.length == 0) { // process no values here } else { for (String[] click : values) { // process your business logic/campaign reactions here } } }}
The following code demonstrates how a recipient’s bounce status can be reset.
/** * Use case: Reset bounce status * This is an example of how to reset the bounce status * of a recipient. */private class ResetBounceStatus extends UseCase { @Override void runExceptional() throws Exception { resetBounceCounter(EMAIL_ADDRESS); } private void resetBounceCounter(String emailAdress) throws WebserviceException { _responseWebservice.resetBounceCounter( _session.getSessionId(), emailAdress); }}
Please sign in to leave a comment.