SOLVED

How do I send a confirmation email with a unique code?

Go to solution
Stephen_Moore
Level 2

Hi,

So there is an upcoming tradeshow and we are giving out free passes to people who submit the form.

There are a limited number of passes, and the pass codes have been provided to us.

I am searching for a way to automatically send out these confirmation emails with the unique codes embedded in the emails.

I also need to know when we have exhausted the codes that we have.

I tried looking on the Nation, but didn't see a solution.

Thanks,

Stephen

2 ACCEPTED SOLUTIONS
SanfordWhiteman
Level 10 - Community Moderator

  1. Create a custom text {{my.passcode}} token local to your program (add a placeholder default value as the token value)
  2. ...

This is a little development heavy method and you'll definitely need a technical person to pull this off. I'll let Sandy confirm if there's a comparatively less dev heavy/easier solution to pull this off! 🙂 Thank you.


Hm. That sounds far too complex. You need to keep a pointer to the most recent code on the stack, which means a separate database. And you need a separate web app to call the REST API!

 

You want to avoid both REST API calls and any (trivially hackable) calls made from the form. All logic should be initiated on the Marketo server side.

 

The better way to do this is via a webhook-compatible service. It shares some of the general logic above. But you can store the codes in a simple text file in Design Studio. Then each time the webhook is called, you increment the pointer by 1 and get the Nth line in the file. Return that in the webhook: done.

 

I’ve done this a bunch of times and if you search my past posts you’ll get some pointers. It’s like < 10 lines of code.

 

Easier still is to “reverse the charges”: have Marketo generate the unique code, then call an external service to say “Hey, I assigned such-and-such code to the lead with this email address.” You can generate an acceptably unique code by mixing together the person’s Marketo Unique Code with the Program ID. The end user will not be able to guess this.

View solution in original post

Jo_Pitts1
Level 10 - Community Advisor

@Stephen_Moore,

if you must use pre-determined codes, then go with @SanfordWhiteman's approach.  A great option for the webhook compatible service he's talking about is flowboost.  Sanford didn't mention it as he wrote it.

 

cheers

Jo

View solution in original post

19 REPLIES 19
Darshil_Shah1
Level 10 - Community Advisor + Adobe Champion

Off the top of my head, here's what you can do -

  1. Create a custom text {{my.passcode}} token local to your program (add a placeholder default value as the token value).
  2. Create an email, plug the {{my.passcode}} token where you want to display the passcode in the email.
  3. Create a trigger campaign with Campaign is Requested trigger source "Web Service API".
  4. In the flow of the campaign use the Send Email flow step to send the email.
  5. You'll need to customize the form submission action to execute below steps, 6 & 7 or built a web-service to do so.
  6. You can choose to store the pass-codes in a stack, and use AJAX calls to query off the pass-code from the top of the stack for each form fill. Make sure you remove the top code after each query to ensure you have un-used pass-code for the next person filling out the form.
  7. Asynchronously call the request Trigger campaign endpoint and each time supply the unique pass code value for the {{my.passcode}} token in the POST request body (the one you got after querying the stack in step 6).
  8. Depending on the platform you choose to store/manage your stack, you can see if a custom alert email can be configured to let you know when the stack gets emptied.

This is a little development heavy method and you'll definitely need a technical person to pull this off. I'll let Sandy confirm if there's a comparatively less dev heavy/easier solution to pull this off! 🙂 Thank you.

SanfordWhiteman
Level 10 - Community Moderator

  1. Create a custom text {{my.passcode}} token local to your program (add a placeholder default value as the token value)
  2. ...

This is a little development heavy method and you'll definitely need a technical person to pull this off. I'll let Sandy confirm if there's a comparatively less dev heavy/easier solution to pull this off! 🙂 Thank you.


Hm. That sounds far too complex. You need to keep a pointer to the most recent code on the stack, which means a separate database. And you need a separate web app to call the REST API!

 

You want to avoid both REST API calls and any (trivially hackable) calls made from the form. All logic should be initiated on the Marketo server side.

 

The better way to do this is via a webhook-compatible service. It shares some of the general logic above. But you can store the codes in a simple text file in Design Studio. Then each time the webhook is called, you increment the pointer by 1 and get the Nth line in the file. Return that in the webhook: done.

 

I’ve done this a bunch of times and if you search my past posts you’ll get some pointers. It’s like < 10 lines of code.

 

Easier still is to “reverse the charges”: have Marketo generate the unique code, then call an external service to say “Hey, I assigned such-and-such code to the lead with this email address.” You can generate an acceptably unique code by mixing together the person’s Marketo Unique Code with the Program ID. The end user will not be able to guess this.

Jo_Pitts1
Level 10 - Community Advisor

@Stephen_Moore,

if you must use pre-determined codes, then go with @SanfordWhiteman's approach.  A great option for the webhook compatible service he's talking about is flowboost.  Sanford didn't mention it as he wrote it.

 

cheers

Jo

SanfordWhiteman
Level 10 - Community Moderator

Indeed! The FlowBoost webhook payload would be like:

var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";
var counter = "/distributed_codes/{{Program.Id}}/v1";

FBHttp.fetch(fileOfCodes)
.then( resp => resp.text() )
.then( respT => respT.split(/\r?\n/) )
.then( codes =>
	FBCounter.count(counter)
	.catch( count => 0 )
	.then( count => 
	  count < codes.length
	  	? FBCounter.autoAdd(counter).then( resp => success(codes[count]))
	  	: failure("All outta codes!")	  
    )
)
.catch(failure)

 

Where sample_codes.txt is a simple text file in your Design Studio with one code per line:

QNFTMGPXLKC2
L09J6I8BTLJF
SQ5L263BDN23
AHDX8LZD91NT
UTWMHM7GFRTV

 

Then the webhook will return one code at a time like

{
    "response": "QNFTMGPXLKC2"
}
{
    "response": "L09J6I8BTLJF"
}

until it runs out.

SanfordWhiteman
Level 10 - Community Moderator

I’ve also been working on a recipe for a very streamlined webhook-compatible service that you can spin up in seconds on  AWS. It does 2 things, and 2 things only:

 

  • remembers how many times it’s been called with a set of parameters (those params are arbitrary and only have meaning to you)
  • loads a remote file and runs a JSONPath query on it

With those 2 simple features you can achieve some really complex stuff.

 

Let’s say you have a file codes.json in your Design Studio:

[
  "QNFTMGPXLKC2",
  "L09J6I8BTLJF",
  "SQ5L263BDN23",
  "AHDX8LZD91NT",
  "UTWMHM7GFRTV"
]

 

Then your webhook URL could be like:

https://hookones.teknkl.com/?file=codes.json&counter=counter1

 

 And the webhook payload is just the one-liner:

$.[${counter}]

 

The variable ${counter} gets replaced by the counter value, so each time you call it the JSONPath changes:

$.[0]​

 

$.[1]

 

$.[2]​

thereby fetching a new code off the stack.

jboconne
Level 1

Hi SanfordWhiteman,

My name is Jeff and I'm assisting my colleague Steve with this task. I'm a web developer  but have zero experience with Marketo and using these built in web hooks.
Do you know of a resource that I can reference, other than this Marketo Nation forum community, that shows step by step, how to build this webhook and connect it to the Marketo workflow?  This is my understanding of the process so far:
1) User fills out the form and submits

2) Marketo replies with an email confirming their submission
    a) during the creation of the email, we call the webhook and retrieve the pass code via : "response": "QNFTMGPXLKC2"

    b) if we have a value, we place the value of the response in a token (a placeholder??)  or 

        if the webhook returns no value (there are no more codes), we may let the customer know that we have exhausted all pass              codes (codes)

3) In your sample webhook code (1st one) , you have two lines at the top

 var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";
 var counter = "/distributed_codes/{{Program.Id}}/v1";

           fileOfCodes is a variable holding the text file, we import that file into marketo and adjust the https://pages.example.... with the actual path where we uploaded the text file


           counter is a variable holding the count. What does or how does the "/distributed_codes/{{Program.Id}}/v1" keep track of the  count?

When creating the webhook, where do we put the sample code? 

 var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";

   var counter = "/distributed_codes/{{Program.Id}}/v1";

   FBHttp.fetch(fileOfCodes)
  .then( resp => resp.text() )
  .then( respT => respT.split(/\r?\n/) )
  .then ( codes =>
      FBCounter.count(counter)
      .catch( count => 0 )
      .then( count =>
             count < codes.length
             ? FBCounter.autoAdd(counter).then( resp => success(codes[count]))
                  : failure("All outta codes!")

               )
             ) 
.catch(failure)

What I really would like to see is how to create a webhook step by step and how to integrate the new webhook in the workflow process.

 

Thanks so much for your help.

 

Jeff
 

SanfordWhiteman
Level 10 - Community Moderator

When creating the webhook, where do we put the sample code? 
 var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";

   var counter = "/distributed_codes/{{Program.Id}}/v1";

   FBHttp.fetch(fileOfCodes)
  .then( resp => resp.text() )
  .then( respT => respT.split(/\r?\n/) )
  .then ( codes =>
      FBCounter.count(counter)
      .catch( count => 0 )
      .then( count =>
             count < codes.length
             ? FBCounter.autoAdd(counter).then( resp => success(codes[count]))
                  : failure("All outta codes!")

               )
             ) 
.catch(failure)

That goes in the webhook Payload textbox.

 

But I think there’s one piece you might not be clear on: you need a FlowBoost API key to make this call. It’s free (Community key is 100,000 calls/month which certainly seems beyond your usage) but you need to fill out the form!

tmoi
Level 2

Hi Sanford!
Thanks a lot, this function is exactly what I'm looking for. I've set everything up through FlowBoost, although I always receive the below response message:

{"errorType":"string","errorMessage":"ERR: Compile error (strict mode): SyntaxError: Invalid regular expression: missing /","trace":[]}

Any idea what might cause this and how should I fix it?
The code you've provided is unchanged basically other than the fileOfCodes path of course.
--
I ruled out the possibility that I've set up FlowBoost poorly, as the much simpler "Hello World!" call went through beautifully with the same setup.
If you need any other details, let me know. Thanks a lot!

SanfordWhiteman
Level 10 - Community Moderator

It’s tricky because in the webhook UI you have to double up those escapes in order for Marketo to send the right thing on the wire. Otherwise Marketo swallows them. Try:

.then( respT => respT.split(/\\r?\\n/) )

 

tmoi
Level 2

Yeah, it works fine now! Thanks Sanford!
I have another concern though, one that might never happen actually but I can not rule out the possibility.
So, when I run the webhook on a sample of 60 records (with 45 codes only), many of them receive back the same code. Only 24 get unique codes in the end, but more importantly, none gets back "nothing" as the value of 15 should because we have fewer codes than people qualified.

 

I realize if my trigger would be closer to a realistic one like "fill out a form" then the possibility of this is closer to 0, as people won't be entering the flow in one batch, but wondering if 2 form submissions are really really close in time, would that result in the same situation described above? Trying it with a smaller sample of 5, adding a 1-second delay between each record's webhook call seems to solve the issue, but it's not scalable. The question in the end is if the payload can be adjusted to have some sort of delay that solves this issue or if the delay should happen in the smart campaign flow. And more importantly, if I'm overthinking it in the first place?:D
Thanks a lot!

SanfordWhiteman
Level 10 - Community Moderator

You’re right that because of multithreading (or, more precisely, multi-processing) on the FlowBoost side that code could return duplicates under high parallel load.

 

You can avoid that by changing the order of operations, so everyone gets a unique counter index before looking up that index (i.e. row) in the file w/values:

var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";
var counter = "/distributed_codes/{{Program.Id}}/v4";

Promise.all([
  FBHttp.fetch(fileOfCodes).then(resp => resp.text()),
  FBCounter.autoAdd(counter)
])
.then( ([fileContents, counters]) => {
  let codes = fileContents.split(/\r?\n/);
  let nextCode = codes[counters.currentCount - 1];
  
  if(nextCode) {
    success(nextCode);
  } else {
    failure("All outta codes");
  }
});

 

tmoi
Level 2

I think the issue still stands. Now running this code on a smaller sample of 20 (still at the same time) continues to return duplicates and one more empty value than it should. Sample: 20 codes, 21 records. 
Result below:

Email AddressLast Unique Code
1 
2Code6
3Code18
4Code18
5Code17
6Code5
7Code12
8Code11
9Code10
10Code11
11Code2
12Code3
13Code17
14Code2
15 
16Code10
17Code17
18Code19
19Code5
20Code17
21Code10
SanfordWhiteman
Level 10 - Community Moderator

Sorry, one important change I forgot to recommend!

 

Use

let nextCode = codes[counters.entryIndex];

 

instead of

let nextCode = codes[counters.currentCount - 1];

 

The 2 differ significantly. entryIndex is the index of the just added entry in the list, which is what you actually want here. currentCount is the size of the whole list, which at certain points in time (under load) may include entries who were added milliseconds after the current person — that’s why currentCount can end up assigning  a code that shouldn’t be given out to this specific person, but to someone else.

 

At any rate, use entryIndex. I tested multiple times with a 50-code file and 50-person list and everything was correct.

tmoi
Level 2

Now it's perfect, thank you!

The explanation helps a lot as well! 

SanfordWhiteman
Level 10 - Community Moderator

Excellent! This needs better/some documentation. 🙂

SanfordWhiteman
Level 10 - Community Moderator

OK, I’m back with more answers! Had a call.

 


3) In your sample webhook code (1st one) , you have two lines at the top
 var fileOfCodes = "https://pages.example.com/rs/111-222-333/images/sample_codes.txt";
 var counter = "/distributed_codes/{{Program.Id}}/v1";

           fileOfCodes is a variable holding the text file, we import that file into marketo and adjust the https://pages.example.... with the actual path where we uploaded the text file

counter is a variable holding the count. What does or how does the "/distributed_codes/{{Program.Id}}/v1" keep track of the  count?

Yes, fileOfCodes points to the Design Studio asset.

 

The code is using FBCounter (actually a simple key-value database, etcd, under the hood) and its method called autoAdd()autoAdd() just adds an automatically-generated unique entry (like a GUID) under the counter path (/codes/12345/v1/...) every time you call it. So it doesn’t have to know what it’s counting — it just counts and tells you how many entries there are!

SanfordWhiteman
Level 10 - Community Moderator

Hi Jeff,

 

I’ll answer in a few parts for readability.

 


2) Marketo replies with an email confirming their submission

    a) during the creation of the email, we call the webhook and retrieve the pass code via : "response": "QNFTMGPXLKC2"

    b) if we have a value, we place the value of the response in a token (a placeholder??)  or 

Wouldn’t exactly say “during creation” of the email here as you’d call the webhook in response to the form fill.

 

In the webhook Response Mappings, you’d set the Response Attribute (left-hand-side) to response and the Marketo Field (right-hand-side) to a new custom String field you create for this purpose.

SanfordWhiteman_0-1645131586652.png

 

That Last_Passcode field will automatically be available as the token {{lead.Last Passcode}} in emails.

 


        if the webhook returns no value (there are no more codes), we may let the customer know that we have exhausted all pass              codes (codes)

Yes, you can detect the error message “All outta codes!” in a couple of different ways:

1. Map the Response Attribute errorMessage to another Marketo Field like Last Passcode Fetch Error or similar, and watch for changes to that field.

2. Trigger on the Webhook is Called activity with the response containing “All outta codes!”.

SanfordWhiteman
Level 10 - Community Moderator

I am searching for a way to automatically send out these confirmation emails with the unique codes embedded in the emails.

To be clear, you have a stack of unique codes (not preassigned) and you want to pull a new code off the stack whenever somebody submits the form, assigning it to that lead?

Stephen_Moore
Level 2


To be clear, you have a stack of unique codes (not preassigned) and you want to pull a new code off the stack whenever somebody submits the form, assigning it to that lead?


Yes, that is correct.
I have a list of codes and need to assign them when the form is submitted.