Skip to content

Plugin CleverReach

Florian von Bracht edited this page Nov 12, 2024 · 2 revisions

CleverReach Plugin

Create your channel like it is described in the output of the Install-AptecoPSFramework command. In the channel settings integration parameter you have the following modes

Mode Upload Data Tag Receivers Copy Mailing Trigger Broadcast Setup
Upload and Broadcast x x x x Upload and Broadcast
Prepare x x x Upload and Broadcast
Integration parameter mode=prepare
Tagging x x Retrieve Existing List Names=True
mode=taggingOnly
Upload only x x Upload only

Modes

Upload and Broadcast

The whole process from uploading data up to the automatic trigger of a copied mailing.

During the process the module will create new local attributes to the new/existing list, upsert data to it, give the receivers a new tag, create a filter/segment, copy a mailing and schedule it a few seconds later.

To create a new list, just enter a name you would like:

grafik

To use an existing list, just open the dropdown and optionally filter it and choose a list:

grafik

With this mode and the prepare mode you are able to use the preview functionalities. So you can interactively enter data and get a rendered personalised email preview back from CleverReach. It looks like this:

Aufzeichnung.2023-07-03.175052-1.mp4

Added support for tagging for all modes. It works in upload and preview and works like in this video:

Aufzeichnung.2023-07-04.113318-1.mp4

Prepare

The whole process from uploading data up to the preparation of a copied mailing. The difference to the broadcast is the not scheduled mailing. Response data will still be able to be mapped as all IDs are already created and saved for matching.

Set to "Upload and Broadcast" Integration parameters like settingsFile=D:\Scripts\CleverReach\PSCleverReachModule\settings.json;mode=prepare

The mechanism for lists is the same as in "Upload and Broadcast"

Tagging

Upload your data and tag your receivers with a specific tag you can choose of. Please make sure you dont setup Upload Only, otherwise the MessageName/Tagname will not be transferred by PeopleStage.

The mechanism for lists is the same as in "Upload and Broadcast"

Upload Only

Please be aware, that you still need to choose a mailing template, but that does not have an effect for the upload.

The mechanism for lists is the same as in "Upload and Broadcast"

Commands

Besides the default commands for PeopleStage functionalities you have additional command you can use straight away after you have imported the module with

Import-Module "AptecoPSFramework" -Verbose
Import-Settings -Path "D:\Scripts\CleverReach\PSCleverReachModule\settings.json"

There are commands available for

Get-LocalDeactivated
Get-ReceiversWithTag
Get-Tags
Get-Blocklist
Get-Bounces
Get-GlobalDeactivated
Get-CRGroups
Get-GroupSegments
Get-GroupStats
Get-GroupStatsByRuntime
Remove-TagsAtReceivers

Debugging

Import-Module "C:\Users\Florian\Documents\GitHub\AptecoPSModules\InvokeCleverReach\InvokeCleverReach"

To change the source code and debug it, start always a new powershell session because modules cannot be overloaded. Do it like if you want to use other credentials

$cred = Get-Credential
start-process powershell.exe -WorkingDirectory "C:\faststats\scripts\cleverreach" -Credential ($cred)

To use the same user, just do it like

start-process powershell.exe -WorkingDirectory "C:\faststats\scripts\cleverreach"

You can save variables and values into the variable $Script:pluginDebug and output it with Get-PluginDebug.

If you don't have this function, you can just put this file in your Public folder and it will be dot sourced the next time:

function Get-PluginDebug {

    [CmdletBinding()]
    param ()
    
    process {

        $Script:pluginDebug

    }

}

Quickstart

If you know what you are doing, just proceed with this guide

# Check your executionpolicy: https:/go.microsoft.com/fwlink/?LinkID=135170
Get-ExecutionPolicy

# Either set it to Bypass to generally allow scripts for current user
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUser
# or
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

# Make sure to have PowerShellGet >= 1.6.0
Get-InstalledModule -Name PowerShellGet -MinimumVersion 1.6.0

# Install PowerShellGet with a current version
Install-Module -Name PowerShellGet -force -verbose -allowclobber

# Execute this with elevated rights or with the user you need to execute it with, e.g. the apteco service user
install-script install-dependencies, import-dependencies
install-module writelog
Install-Dependencies -module aptecopsframework


# Import Module and install more dependencies
Import-Module aptecopsframework
Install-AptecoPSFramework -Verbose

#-----------------------------------------------

# Please open another PowerShell window to enforce a reload of that module, recommended with elevated rights, if the plugin has dependencies

# Change to the location where you wish to install the plugin to
Set-Location -Path "C:\Apteco\Scripts\AptecoPSFramework\CleverReach"

# Import the module
Import-Module aptecopsframework -Verbose

# Choose a plugin
$plugin = get-plugins | Select guid, name, version, update, path | Out-GridView -PassThru | Select -first 1

# Install the plugin before loading it (installing dependencies)
Install-Plugin -Guid $plugin.guid

# Import the plugin into this session
import-plugin -Guid $plugin.guid

# Get merged settings for this plugin and change some
$settings = Get-settings
$settings.logfile = ".\file.log"
$tokenFile = ".\cr.token"
$tokenSettings = ".\cr_token_settings.json"

# Set the settings
Set-Settings -PSCustom $settings

# Create a token for cleverreach
Request-Token -SettingsFile $tokenSettings -TokenFile $tokenFile -UseStateToPreventCSRFAttacks

# You are getting asked for a secret, just paste it interactively
# The secret should look like: JQZrcjW2gJtr93bvys4GFVeaUCTecpa

# Save the settings into a file
$settingsFile = ".\settings.json"
Export-Settings -Path $settingsFile

# Register a task for automatic token refreshment
# You will be asked for a user to execute the task with
Register-TokenRefreshTask -SettingsFile $settingsFile

#-----------------------------------------------

# Please open another PowerShell window to enforce a reload of that module, recommended with elevated rights, if the plugin has dependencies

# Import the module and the settings file, which contains the plugin settings, too
Import-Module aptecopsframework -Verbose
Import-Settings -Path ".\settings.json"

# List all commands of this plugin
get-command -module "*CleverReach*"

# Then you can use commands like these
Test-Login
Get-CRGroups
Get-Messages
Get-Tags
Get-Bounces
Get-Blocklist


#-----------------------------------------------

# To manually refresh your token later, just execute

Save-NewToken

CleverReach Settings

Please review DefaultSettings.ps1 in the modules folder AND the plugins folder for more information. Some of the settings are explained here in detail.

  • Add more explanations
Path Setting Default Explanation
/ base https://rest.cleverreach.com/v3/ The default API address for CleverReach
/ contentType application/json; charset=utf-8 Default content type that will be used for API requests
/ pageSize 500 If paging is used to read information, this is the default pagesize that will be used automatically
/ mailinglimit 999 No of mailings that will be loaded
/ additionalHeaders additional headers that should automatically be included in the API requests
/ additionalParameters additional parameters for the Invoke-RestMethod e.g. proxy parameters
/ logAPIrequests true Output GET and POST requests in the console window
/errorhandling/ HttpErrorDelay 200 Delay for next try in case of an exception
/errorhandling/ RepeatOnHttpErrors [502] http errors array that should get the number of retries from MaximumRetriesOnHttpErrorList
/errorhandling/ MaximumRetriesOnHttpErrorList 3 Repeats for specific http errors that are catched
/errorhandling/ MaximumRetriesGeneric 1 Repeats for generic errors that are not specifically catched
/token/ tokenUsage consume consume or generate, depending on the mode you are wishing
/token/ tokenFilePath path for the file containing the token that should be consumed or generated
/upload/ countRowsInputFile true Automatically count the number of rows in the input file. This uses streaming and does not parse anything, so it is extremly fast.
/upload/ validateReceivers true Uses a CleverReach API call to validate receivers. It removes blacklisted, not active and not in the list contained emails addresses.
/upload/ excludeNotValidReceivers false If this is set to true, only active email addresses of the specific list will be used. This does only have an effect when using existing lists. So new contacts will not be uploaded, only existing ones in CleverReach will be used instead.
/upload/ excludeBounces true Exclude bounces from upload
/upload/ excludeGlobalDeactivated false Exclude deactivated (unsubscribed) receivers from any list (groupid=0)
/upload/ excludeLocalDeactivated true Exclude deactivated (unsubscribed) receivers for the chosen list
/upload/ uploadSize 300 Max no of rows per batch upload call, max of 1000
/upload/ tagSource Apteco Default tag source that will be used like Apteco.a1qhvh3_20230607201732
/upload/ useTagForUploadOnly true adds a tag to receivers, even if no email gets prepared or send out
/upload/ reservedFields ["tags"] field names that should not be used in uploads
/upload/ loadRuntimeStatistics true Loads total, active, inactive, bounced receivers of the group after upserting the data. This loads all receivers on the list, so can need a while and cause many api calls
/broadcast/ defaultReleaseOffset 120 Seconds offset that will added to the current time when broadcasting a mailing
/broadcast/ addPreheaderAfterBody true Adding a default preheader after the <body>
/broadcast/ preheaderFieldname AptecoPreheader The variable/field name that will trigger a preheader insertion/replacement.
/broadcast/ removeNativePreheader true Sometimes CleverReach already inserts a preheader into the template. This command removes the native CleverReach Preheader
/broadcast/ defaultContentType html/text We cannot read the content type of the mailing, so we are setting it here. Could be "html", "text" or "html/text"
/broadcast/ defaultEditor eddytor We cannot read the used editor from the template so we are setting it through this entry. Could be "eddytor", "wizard", "freeform", "advanced", "plaintext"
/broadcast/ defaultOpenTracking true We cannot read from the template if the open tracking is active or not. So it will be set through this setting.
/broadcast/ defaultClickTracking true We cannot read from the template if the link/click tracking is active or not. So it will be set through this setting.
/broadcast/ defaultLinkTrackingUrl Could something be like "27.wayne.cleverreach.com"
/broadcast/ defaultLinkTrackingType Could be "google", "intelliad", "crconnect"
/broadcast/ defaultGoogleCampaignName Something like "My Campaign" for tracking reports in Google Analytics
/broadcast/ waitUntilFinished false PS or Orbit are waiting until mailing is confirmed to be sent off
/broadcast/ maxWaitForFinishedAfterOffset 120 Wait for another 120 seconds (or more or less) until it is confirmed of send off
/response/ useSeparateLogfile false Change this to true if you want to use a separate logfile
/response/ logfile .\response.log The logfile if you decide to use a separate logfile
/response/ urnFieldName urn Primary key field name, which should be global and is needed for matching
/response/ communicationKeyAttributeName communication_key The local group attribute that will be loaded from the group, not used yet
/response/ filePrefix responses_ Prefix for the response files that are generated
/response/ messagePeriod 60 How many days do you want to go backwards for loading mailing reports?
/response/ responsePeriod 120 How many days to you want to go backwards for response data per message? Normally this numbers is smaller than the messagePeriod
/response/ saveLastTimestamp true Save the current timestamp at the end of the response download
/response/ saveLastTimestampFile .\lastresponsedownload.json Where to save the current timestamp?
/response/ loadSent true Load confirmed email deliveries
/response/ loadOpens true Load open reactions (if tracking is allowed in CleverReach)
/response/ loadClicks true Load click reactions (if tracking is allowed in CleverReach)
/response/ loadBounces true Load confirmed bounced emails
/response/ loadUnsubscribes true Load unsubscribed emails based on a mailing/group
/response/ triggerFerge true Should ferge get triggered after the response download is finished?
/response/ fergePath C:\Program Files\Apteco\FastStats Email Response Gatherer x64\EmailResponseGatherer64.exe Where is the FERGE exe located?
/response/ fergeConfigurationXml D:\Scripts\CleverReach\PSCleverReachModule\responses.xml Should be changed for the correct path. This xml file should be created with the FERGE configuration tool

Response Gathering

This plugin has a functionality builtin to load responses with a command.

Configuration

There are three important requisites:

  1. Install the FastStats Email Response Gatherer from Apteco on the same machine
  2. Create a configuration xml file when executing the configurator at C:\Program Files\Apteco\FastStats Email Response Gatherer x64\EmailResponseConfig.exe. Please fill out and then save the file where you like it:
  • Connection String: Your email response database connection string, usually something like Data Source=localhost;Initial Catalog=RS_Handel;User Id=serviceuser;Password=password123;
  • Bulk Insert Folder: A folder that is temporarily needed for inserting the data. This path needs to be accessible by the SQL-Server as if the SQL-Server would enter this path
  • PeoplStage connection string: Your PeopleStage database connection string, usually something like Data Source=localhost;Initial Catalog=PS_Handel;User Id=serviceuser;Password=password123;
  • Broadcaster: PowerShell
  • Username: Could be any dummy value
  • Password: Could be any dummy value
  • Broadcast Parameters: Please have a look at the following table and check each parameter, especially FTPURL which points to your folder where you are saving your response files:
Parameter Value
CLICKDATECOLUMNNAME timestamp
CLICKURLCOLUMNNAME link
DELIVERYDATECOLUMNNAME timestamp
EMAILCOLUMNNAME email
EVENTTRIGGEREDDATECOLUMNNAME timestamp
TYPECOLUMNNAME MessageType
URNCOLUMNNAME urn
DATEFORMAT UnixTimeStamp
RemoveFiles true
MESSAGENAMECOLUMNNAME mailingName
FILEPATTERN responses_*
FTPURL File://D:\Scripts\CleverReach\PSCleverReachModule\r
DELIMITER TAB
ENCLOSER DOUBLEQUOTE
SENDIDCOLUMNNAME mailingId
  1. Check your settings json file
  • So please check your settings json file that you have configured this section. Is it important you have checked at minimum the following settings:
    • fergePath: The path to your response gatherer, usually something like C:\Program Files\Apteco\FastStats Email Response Gatherer x64\EmailResponseGatherer64.exe
    • fergeConfigurationXml The path to your xml file that you have created in the previous step

Gather Responses

Just execute these commands which can also be used for a scheduled task. Please change to the directory where you wish to save the response files to.

Set-Location -Path "D:\Scripts\CleverReach\PSCleverReachModule\r"
Import-Module "AptecoPSFramework" -Verbose
Import-Settings -Path "D:\Scripts\CleverReach\PSCleverReachModule\settings.json"
Get-Response

As per default, FERGE should be automatically triggered after downloading and parsing the response data.

Automatic Token Refreshment

Still needs to be implemented here. In the meantime have a look here: https://github.com/Apteco/HelperScripts/tree/master/scripts/cleverreach/check-token

We are using a already existing and prepared apteco app to make this happen. This app has some privileges that you don't get by default. So for debugging purposes you can copy this plugin and change your clientid, clientsecret and redirecturi, but we would recommend to use the Apteco App. Please be aware, we are not getting notified about the app usage and don't have any access on the data. The app is only your kind of gateway to your account through the API.

FAQ

Cleaning

cleanup of tags cleanup of segments cleanup of lists

Usage of multiple settings files

It is supported to have as many settings json files as you wish. Just enter a different filename when you do Export-Settings -Path ".\settings_new.json and put the absolute file name into your channel editor integration parameters.

Remove multiple tags at once

It is easy to combine multiple commands like

Get-Tags | where { $_.origin -eq "Apteco" } | % { Remove-TagsAtReceivers -Source $_.origin -Tag $_.tag }

This command gets all tags, filters it by the first part of the tag and removes this tag from all receivers

Here is another example to remove tags that are older than 30 days

get-tags | where-object { $_.origin -eq "Apteco" -and  [datetime]::ParseExact($_.tag.substring($_.tag.IndexOf("_")+1),"yyyyMMddHHmmss",$null) -lt [datetime]::now.AddDays(-30) } | % { Remove-TagsAtReceivers -Source $_.origin -Tag $_.tag }

Listing of all segments

This can be easily done with

$segments = Get-Groups | % { Get-GroupSegments -GroupId $_.id }
$segments

Download of all receivers of all lists as json files

Get-CRGroups | % { $g =$_; Get-ReceiversFromList -ListId $g.id | ConvertTo-Json -Depth
99 | sc -Path ".\$( $g.name  ).json" }

Support of Preheader

Yes, this plugin allows the support of Preheaders. This is not possible to gather from CleverReach API at the moment, so we are using regular expressions to cut out existing preheaders and set a personalised one, which can also use Variables. The removal and replacement only takes place, if you define a preheader variable in Apteco with the Name AptecoPreheader (not case sensitive). So you see Apteco on the left hand side and my inbox on the right hand side:

grafik

The email on the right hand side with preheader also shows an example above how it looks like without a defined preheader variable.

This behaviour is dependent on the broadcast settings named addPreheaderAfterBody and removeNativePreheader

The preheader html is defined as

<div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;">{APTECOPREHEADER}&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;</div>

If you want to empty to your preheader column, please use null as field value in PeopleStage or Orbit.

Deactivated / Unsubscribed receivers

The settings upload.excludeGlobalDeactivated (default: false) and upload.excludeLocalDeactivated (default: true) are controlling this behaviour.

If excludeGlobalDeactivated is set to true and if there is a receiver deactivated on one list and is active on another list, it will be in the result as deactivated.

There is also a setting in CleverReach that puts a deactivation/unsubscription automatically on a Blocklist. This setting causes that those contacts are automatically excluded from uploads in Apteco but also automatically excluded in CleverReach. So it is a double safety net.

Difference to C# Implementation

There is another already integrated implementation available that uses an older approach where receivers are getting activated and deactivated before the upload when working on existing lists. New lists will be filled with only active receivers. If you already use this implementation, there are two differences:

  1. URN field: In the Channel Editor you define the URN field as a parameter. This is not supported yet. So you need to add your URN to the additional variables and give it the label you wish to (like CustomerID).
  2. Communication Key: Beforehand, the communication key was always created in CleverReach with an underscore in the name and the description like COMMUNICATION_KEY. Now spaces are allowed and lead to an error in PeopleStage and Orbit that shows: Error[9001]: Failed to sync attributes. In the detailed log file you also see an HTTP409 Conflict, because the communication key should be created but is already there. Since version 0.0.9 this module will automatically look for a not existing communication key and communication key and communication_key, so the parallel use of the existing integration and this framework is possible on the same list (but possibly different impacts as the existing integration deactivates receivers).

Updating the settings after an module/plugin update

It is pretty simple now. Just update your module with

Import-Module AptecoPSFramework -Force

And then execute an import and export. Doing this you are ensuring you get all new settings options into the settings.json file. Existing (changed) settings won't be overridden and the existing file will be renamed with an attached timestamp, so it will not be deleted.

Import-Settings .\settings.json
Export-Settings .\settings.json

TODO

  • get lists
  • get mailings
  • migrate "refresh token with scheduled task" to here
  • setup boilerplate (copy files of a subfolder to somewhere else and hints, that this folder needs to be accessed by a e.g. service and hints to the paths for get-messages etc.)
  • cleanup job of lists and tags -> cmdlets already implemented
  • put token in a separate file (or give the option for it to use multiple settings). Or maybe have a "main" settings file and give an option to export the token and in the other settings file use that one like PeopleStage, too
  • check the validations about bounces
  • implement and test tags in a field, especially for preview
  • Try an overlay in preview to edit mailing
  • Try to use regex to identify used variables in mailing html and show in preview
  • Umlaute in filenames in debug mode
  • debug mode not set in the plugin itself

Test

  • additionalParameters and additionalHeaders
  • exception for api call
  • dependencies
  • Differentiate between new lists and existing lists
  • test reserverd fields, tags
  • check the processid
  • manually expire a token and test the stacktrace
  • test on multiple table levels and their dependency with URN