MARDREAMIN’ SUMMIT 2025
MAY 7-8, 2025 IN ATLANTA - GA

Days
Hours
Minutes
Seconds
🎉 The Event Is Live! 🎉

NOW PLAYING

View the session live or catch the replay here. You’ll find the recording and all related resources on this page once available.

Looking for the Chat?

Our live discussions are happening over in Slack. That’s where you can connect with speakers, join session threads, and chat with other attendees in real time.

How to send a Pardot Email with Multiple Line Items

It is impossible to send a Pardot email that has a list of related records… or is it?

In this session, we will uncover strategies to send a Pardot email with multiple line items. We’ll walk through a hypothetical use case at a realty company by going step-by-step through an email build. The email will send prospects many personalized property listings that may interest them.

adam erstelle headshot
Sercante

Adam

Erstelle

Keep The Momentum Going

Gemini and Marketing Cloud at scale

Increase your Marketing Qualified Lead Pipeline with Agentforce

Video Transcript

Speaker 0: Hello, Thank you for joining us today. Uh, we’re here with one of Sercante’s own gurus, Adam Erstel, and he’s here to prove to us that it is possible to send a Pardot email with multiple line items. Take it away, Adam.

Speaker 1: Thanks, Pam. Alright. So as Pam said, I’m Adam Erstel. I work with Sercante. I get to build some really cool things. You might have seen some of them on our Sercante Labs page. If you haven’t, check them out. Um, Yeah. So let’s dive right in. So what I’m hoping to do today is help people of different technical depths come away with something of use. Right? So I’m gonna have recipes that’ll be helpful for business user business users, little bit of the marketing folks, gonna have some pseudo code and some APIs that’ll help have help you guys be able to have these discussions with your developers. And at the end, I’m gonna actually have real code on the screen, and we’ll go through a little bit of that. Um, at the bottom of the of every slide, I’ve got a link to a GitHub repo. It’s also in chat. You can go there, take a look at the sample that I’ll be going through. You can tear it apart, do whatever you want. So when we’re talking about multiple line line items, what do what do we mean? Right? So, basically, it’s just you got one email that’s gonna show more than one thing. Right? So well, more than one thing. What do you mean? So it could be multiple products coming from a recommendations engine or maybe renewal information. Right? Could be four or five blog posts that you want people to read. Right? It’s very similar to our sponsor Feed Otter. Right? Four or five blog posts, multiple line items. You can have what we’re gonna be going through today, multiple real estate listings. Right? So post in chat if you have other ideas of multiple line items or some things that you’ve tried to put together in a Pardot email in the past. So today, what are we looking to actually put together? Right? So we’re gonna have a single prospect email with a bunch of real estate listings. Right? So it’s gonna be a a simple template. We’re gonna not know how many, um, real estate listings are gonna be known when we’re creating the template, and each prospect might get a different set of listings based on their interests. Alright. So it’s it’s cool that we wanna build that, but how are you gonna get there? Right? So I’m gonna go through the process that I tend to go with with our clients when we’re looking to put something like this together. Right? And the first thing you really need to do is figure out what is it that you’re looking to build. Right? So there’s a few questions here that we’ll go through. Right? So where is this email template gonna actually live? Right? Where is the HTML gonna live? And, really, you have two options. Right? It can be inside Pardot with a Pardot email template, or it can be outside of Pardot, and there’s benefits to both approaches. Right? When it’s inside Pardot, and that’s my favorite, to be honest, marketing can make tweaks to the template without engaging a developer. Right? You have your Pardot email reporting capabilities, but you need to kinda drive Pardot in a slightly different way. If it’s outside of Pardot, right, you really have the power of whatever you’re using to build the email. Right? So that could be a templating engine in various developer languages. You know, the capabilities are just almost limitless there. Now is the email gonna be different between prospects? Right? So if it is gonna be different, then you really need to figure out or build the HTML differently for each prospect. Or if you’re using that Pardot email template, you’re gonna really need to leverage custom fields, and I’ll get into that in a moment. Now if everyone’s gonna see the same list of things, right, so blog post is is a great example. Right? You can figure out that HTML or the email content, and then you can just send it to a list of prospects. Right? Or you can still do it with, you know, the way that you do right now with a list send. Right? Another thing to consider when you’re looking to put something like this together is how many prospects are we emailing. Right? What’s the scale? And while 5,000 isn’t really a hard number, it’s one that we tend to use. Right? So if you’re sending it to less than 5,000, well, then you’re the thing that you’re putting together, right, how you’re using the Pardot API, it can be a lot more forgiving in the approach. If you are starting to send a higher limit, then you really need to be careful of the Pardot API limits per day, um, and various other things. Now can that prospect get more than one email in a single send? Right? So if not, you can use one to one emails, or you could use your list sends. That’s pretty straightforward. But if a prospect could get more than one email, right, maybe I don’t know. It’s a it’s a bad example. A single person is working with two real estate agents. Right? And they’re gonna get their property listings from each agent, maybe with different preferences or, you know, they told the real estate agent different things. Right? So if you’re gonna get more than one email in one of these batch sends, then, again, you can still use your one to one emails for low volume, and this is all driven through the API. And if you’re looking to do list sends, then you start need to think about how you’re gonna organize these list sends. Right? So you can have a a new static list for everybody’s first email, then you can have a second static list for all the people who are getting a second email and so forth. So how do we get there? So looking at our email template again, thinking about those discovery questions, we have we’re gonna have our template in Pardot, and I have an example where it’s not. The email is gonna be different for each prospect. We’re gonna be looking at three test prospects as part of this demo. Right? Don’t wanna have a something too crazy. And for our example, a prospect will not get more than one email in the send since we only have three. So now I’m gonna start getting into the the recipes. Right? So we’ll have the recipe, which will include pseudocode. Right? And, well, what is pseudocode? Really, it’s just, like, human bullet points that represent what a developer would look to build. With this first example, everyone’s gonna get the same email, and it’s gonna be an external template. Right? Feed Otter likely does something very similar to this approach. So what we would do is we would load the original email template that might have placeholders in it. We’re gonna go grab those line items. Right? Blog posts, property listings, I don’t know, product recommendations. Then what we do, basically, we we smash them together, right, so that we have a final HTML product. Then what we do is we use the API to log in to Salesforce, and we use the API to send a list email. So it’s pretty simple here. Going to next level, very similar. We’re we’re still working with that external template, but now we want everybody to receive an individual personalized email with their own line items. So kinda similar to before, we first need to get a list of the people who need to get an email. Right? Who are all the recipients? Then I can go grab that original email template with the placeholders. I’ll log in to Salesforce. Then for each email or each recipient, I’m gonna go get their specific line items, right, their property listings, their product recommendations, whatever it is. I’ll combine their items with the email template, smush it together so that we have the final result, and then I can use the Pardot API to send that one to one email. Now before we get into the recipes and pseudo code for actually sending all of this through a Pardot email template, and for those who are pretty familiar with Pardot, you can’t really do this natively. Well, when we’re using the API, we can do it, but we really need to cheat. Right? And what we’re gonna do is we’re gonna flatten those multiple line items into a whole bunch of prospect custom fields. Right? So when we’re thinking about the line item and all the attributes, right, maybe there’s a name, a description, a a web page URL, and an image URL. Right? So if you have those four or five fields for each line item, then you have to start thinking about, okay. Well, in my email template, how many line items will be the maximum that I’ll show in the email template? Right? You don’t wanna ask your database guys how many is possible because they’ll come up with a ridiculous number like two or 300, and you’re not gonna send an email with two or 300, you know, property listings. Probably highlight five or six with a link saying click here to see all of them. Right. So when you got your five or six let’s pick one of those so that we can do some easy math. You got six line items. You got five fields. That’s about 30 custom fields you’d be adding to support this email template. So that’s good for the custom fields. Let’s talk about the actual email template itself. Right? So in Pardot, your HTML would be need to be written and designed assuming that max number of items already there. Then you could use your HML to put the values coming in from the prospect record, and you would use HML conditional statements around each block. Right? So, basically, what we’re saying here on screen is if there is a fifth listing in the custom fields, then I wanna render the HTML block for that entire listing. Right? And then you’d have your your div tags or your table tags with all of your headings and images and all that fun stuff. So, again, your template needs to be designed and written supporting that maximum number of items, and you’d use your conditionals to control how much of that email actually gets presented or rendered to the user. So for the demo today, this is a listing of all the custom fields that I have built in my Pardot org in order to support the demo. Right? So you can see a pretty common pattern here. I’ve got a prefix that lists, you know, what are these fields for. Then I’ve got for each listing, I’ve got what was it? Seven seven fields. Right? You got the price of the listing, number of bedrooms and bathrooms, square feet, etcetera. At the bottom of the first column, you’ll see a couple of fields that aren’t line item specific. Right? So I’m actually gonna have the count of the listings in the email template as well as the agent name for a call to action. Going back to our recipes, now that we know that we need a whole bunch of custom fields in order to house all the right data, well, now we can start thinking about, well, what does that recipe look like? Right. So similar to the previous one where we had an external template, here we have a Pardot template. We’re still gonna need to get that list of people who are receiving the email. Right? Prospects, recipients, whatever you wanna call. Then for each person, we need to get the line items. Right? Get the property listings, get the product recommendations, whatever it is. Then we need to actually calculate what all of those custom field values should be. Right? So PowerDreamin’ 2021, listing number four, the price is $250,000. You need to do that for all of the line items for all of the fields. Once you have all of those field updates ready, then you can use the API to update the prospect. Right? So now Pardot has all the values that you want. You’ll use the API to send a one to one email. Then what I highly recommend is you use the API again to update the prospect, and you clear all those values out so that a Pardot has a nice clean record. So that maybe next week when you’re gonna go send a new email, you don’t have to worry about well, last week, I had six line items, but this week, I only have four. And what’s gonna happen to number five and six? By clearing it all out, you don’t have to worry about it for the next email sent. Now if you’re starting to deal with larger numbers of emails that need to go out, you might need to use the Pardot batch update API. This one gets just a little bit more tricky, right, when you’re looping through each person. Instead of calling the API to update them, what you’re doing is you’re adding them to a batch. And the way I kinda describe this is imagine a bucket of water. Right? Once you start filling your bucket up, once it’s full, then you can throw that bucket of water at Pardot saying update all of these fields for, you know, 30 to 50 different people. And you can keep, you know, slowly filling up the bucket, emptying it until, you know, the puddle that you’re trying to work through is has dried up. Once all of the prospects have their values, then you can use the API to send the one to one emails. You can look to start calculating those empty custom field values, and then you can do that same batch approach to clear everything out after the fact. Now if we’re starting to look at using list sends, right, instead of doing the one to one emails, you’d still go through the batch approach to set all the field values. You might wanna add someone to a brand new static list if you don’t have one chosen already. And then once all those prospects on that list have the right values calculated and updated, single API request to send that list email. Now what’s important here is you actually have to wait for Pardot to send that email before you clear everything out. Right? And it could take ten minutes. It could take half an hour depending on how quick and how nimble Pardot is feeling that day. You really wanna make sure that email gets actually sent and delivered before you clear those values. I’ve never had to use this recipe myself yet, but if you’re starting to deal in the tens, hundreds of thousands of prospects, right, you could start to leverage the import API as opposed to the batch update. Again, I haven’t really seen it needed to be used, but should you be in that massive volume of emails that need to be sent, this is an option for you. Alright. So with all of those recipes and, you know, um, patterns, it’s great to to know them, but we need to build it. Right? We need to figure out how it’s actually gonna be done. So because this isn’t native, this is something that needs to be put together. Whatever you’re looking to put together, it needs to live somewhere. Right? So you could use an integration platform as a service. Right? We’ve we’ve had a couple of sessions on that in ParDreamin’ earlier I think it was yesterday. Um, but you can use platforms like tray.io, MuleSoft, Jitterbit, you know, whatever whatever platform you are familiar with today, take a look and see what you might be able to leverage. But odds are you’re not gonna be able to leverage one of these platforms, and you’re gonna have to actually build some code. Right? Now I can’t stress this enough. Whatever you’re looking to build, it doesn’t matter what kind of language or where it lives. Right? It’s whatever your team or your developers or whoever. It’s whatever they can actually build and support. It can be Python a Python script on a laptop. Right? That’s what I’ll be showing you later today. You could write Apex code in Salesforce. I wouldn’t wanna do it for this type of a solution, but you could. You could have your workflow in Trio, Java code on Heroku. Right? Doesn’t really matter. It needs to live somewhere so that it can run. Okay. So now we’re at a demo time. So the code sample, as I mentioned at the beginning, it’s available on GitHub. Go ahead, copy it down, clone it, whatever. The package that I have prepared, there’s a few different scripts in it. Right? So we have a script for creating and deleting the custom fields that support this demo. Right? In the various environments, I was trying to practice this and and develop it. I was getting really tired of creating 40 custom fields with each environment, so I made a script that made it very easy. So once the custom fields are there, I’ve got three email send scripts that we’re gonna go through in a minute. So the first one will send pre rendered HTML directly to prospects. So that’s an example of an external template that we’re gonna use and say, hey, Pardot. I’ve already figured out the HTML. Just please deliver this to Pam. The other two scripts are, again, more of my favorites where we will update the prospect in Pardot, then we’ll tell Pardot to send the email with a template. And we’ve got the one to one, and we have a list send example. Now because this demo sends emails, it only fully works in production. Right? Pardot sandboxes and Pardot dev orgs don’t actually send emails, But that doesn’t mean you could or couldn’t run this demo yourself in one of those environments. Just play with it and see how it’s behaving. Alright. So let’s dive into a demo. Alright. So the first thing I wanna show in this demo is in order for any code to work with Pardot, you need to set up some sort of configuration. Right? So in Salesforce, there’s a bunch of different steps. We have all these steps in a read me with some blog posts, but it’s really important that you get your Salesforce username, password. In this example, we have the security token and a few other things. Right? So once you’ve set up Salesforce so that code can work with the API, you fill this section in. On the Pardot configuration, really, what we need is the business unit ID. If your org does not support the allow multiple prospects of the same email address, You would need to change your API version from four to a three. And what we would need to do is copy or we would need to create a Pardot email template. And I’ve got the HTML right here. So you can go in there. You can copy the HTML. In Pardot, you would create a new email template, paste it in, fill in the other fields. And once you’re good to go, you’d need that email template ID. Right? So it’s a five or six digit, uh, ID, and you’d paste it in here. We would also need some test campaign or something like that. So I’ve got all these values filled out in my actual configuration, which I’m gonna try to not share on screen. And, uh, once that’s done, the demo should be able to talk to your Pardot instance. So we’re gonna take a look at the first email script. So the approach that I’m taking here is first thing we’re gonna do is we’re gonna read that configuration, that app dot any file that we just talked through. We’re gonna read all those values in. Then what we’re gonna do is we’re going to connect to a data source or another API or something in your business that’s gonna say, these are the people that I wanna send an email to, and these are the line items that I want to include. Right? For this demo, they’re just hard coded CSVs in this data directory. But in the real world, you’d be connecting to, again, one of your own databases or applications, recommendation service, recommendation engine, whatever. So now that we kinda know where all our data’s coming from, we got our configuration, now we can actually get going. So the first thing we’re gonna do is we’re gonna log in to the Salesforce org, and we’re gonna get our email template. And this script number two is using an external email template. So I’ve got the email in here or sorry. I’ve got the HTML in this particular file, complete HTML template. So it loads in that template into the script. Then I get the recipients. Right? So getting the recipients that need to get this weekly email. I loop through my recipients. Right? For each recipient, I want to get the listings for that particular one. Now for this demo, we’re just doing a random sampling of property listings. We’re not actually there’s no intelligence there. Then what we do is we smash the listings or the line items with the external email template, and that gives us the complete HTML that we wanna send. Now because this is a demo, I get to cheat a little bit. I’m not doing the same thing for the text version, but you really would want to. So once we’ve got everything ready, we can say, hey, Pardot. I want you to send an email to a particular Pardot prospect. Right? So that’s the URL that we’re putting together. In the request data, this is where we need to provide the campaign ID. We need to provide that text content. Again, I’m cheating here. The name, the subject, who the email is coming from, and the HTML content. Right? So that’s kind of the the API payload that we’re sending to Pardot saying this is all the information. Please go. Then we have our request headers, which basically say, yes. I’m allowed to talk to Pardot, and this is the business unit that I’m working with today. So this line 53 is where we are actually executing the API request to send the email, then we’ll check to see if it was successful or not. In the real world, yeah, you would do something a little bit more than just, you know, debug statements, but, again, demo cheating. It’s awesome. And then the script has executed successfully. So I’m gonna go ahead and actually run that script. So we can see here that we have three recipients. Is getting five listings, Luminara is getting five, and Zam Wessel is getting four listings. So let’s go take a look at my email. So Gmail kinda threaded the two people that are getting five, but so let’s take a look at, uh, Zams. So they get four listings. Right? The call to action has Zams’ real estate agent’s name in it. We’ve got the listings with different values. That’s cool. Let’s delete it. So here we’re looking at Shakti’s email. He’s got five listings. That’s kinda cool. And Luminara has a different set of five listings. Awesome. So that’s our that’s our first example. Let’s take a look at our second script. Come on. Let me resize you. Alright. So similar to the previous script, we’re getting our configuration. We’re gonna figure out where our data’s coming from. We’re gonna loop through all of our recipients. So the difference here is we actually need to figure out the prospect fields that we need to calculate. So the first two at the top aren’t line item specific. Right? We wanted the count of listings, you know, for the subject line merge field. We wanted the agent name for the call to action. Now for each listing, we need to figure out, you know, what is the Pardot API field name for price for listing number one? Once we figured out that name, we can add the actual price for listing number one to the prospect for, you know, par dream in 2021 underscore listing one underscore price. And we repeat that calculation for each of the fields for each line item. So at the end of all these field calculations, we’ll have 42 or 44 custom fields ready to get updated. We’re gonna use the Pardot API to actually update the prospect. Now we can get ready to call that Pardot API request to send the one to one email again. So very similar for the URL. We wanna send it to a specific prospect. What changes in this request is the request data is a lot simpler. Right? Because we’re telling it, hey. I want the I want you to use an email template. I wanna specify the campaign and the prospect ID. That’s all that’s needed. Right? Because when you built the email template in Pardot, you provided all that other information. Who is it coming from? What’s the subject? Blah blah blah. Like before, we have a line here to actually fire off that API request that we’ve spent all this time preparing. We check to see if it worked. And then afterwards, we will clear all those values out and do another API request to update the prospect. So let’s run sample number two. Alright. Chuck t is getting five. Luminar is getting six, and Azzam Wessel is getting three. Let’s check our email. Alright. Shakti’s got five. You know, I’ve looked at these so many times with my practice runs, and and here, I can’t even remember if these were in this previous email or not. But, uh, you know, one thing to note with this particular one, because we’re doing a random number to pick listings, right, we just happen to get the same random number twice. So that’s why we’re seeing the same one here. In in a real world, hopefully, you wouldn’t see the same property listing twice, but, again, the joys of cheating in a demo. So who is who is this one for? This one’s for Luminara, you know, six listings, and I think you get the idea here. So our third code sample, which I’m not gonna run because it is asking Pardot to do a list email, and, you know, list emails can take ten, twenty, thirty minutes as much as I’d love to hang out with everyone for that time. I’m sure we all have more important things to do, other sessions to check out. So for this script, same as before, you know, I’m getting my configuration where the listings are coming from. I’m authenticating into Salesforce. What’s different is before I start looping through my recipients, I’m gonna get my, uh, batch ready. Right? So, So, basically, what I’m doing is I’m getting my empty pail ready to start bringing on water. In a production scenario or in a real scenario, you wouldn’t have a batch size of two. Right? It just you’d start off at 50. Right? I wanna update 50 prospects at a time with a single API request. But because this is a demo, we’ve only got three people. I’ve greatly reduced that to two just so that we can kinda see, you know, a full bucket being thrown and a half empty bucket being thrown. So now that our bucket has been built, so to speak, we can start looping through our recipients. Right? So we’re gonna get the listings for each recipient. We’re gonna prepare all those prospect fields. Right? The 44 custom fields that’s all being handled in this function that’s buried. Right? Then we’ll then we’re gonna append that prospect into the bucket. Right? So we’re taking that cup of water. We’re pouring it in. Then as we’re looping through all of our prospects, we’re gonna say, hey. Is the bucket full? If it is, let’s throw it at Pardot. Let’s empty the bucket, and let’s keep going. Right? So this could work for hundreds, thousands of prospects. Once we’re done processing all of our recipients, we might have a partially full bucket. Right? So what we can do is say, once we’re done, we’re gonna check our bucket. If there’s any water left in it, let’s throw it at Pardot again. So now we’re done updating all of the prospects. Now we can send our email. So we’ve got our URL being prepared here. And what we’re doing, you’ll note there’s no prospect ID in this email sorry, in this URL. Right? And that’s because we’re using a list. In the payload, just like before, we’re saying we wanna use this campaign. We wanna use this email template, and here are the list IDs that I want to include in my list send. Now if you check the Pardot developer documentation, there’s also another argument for suppression lists if you wanna get fancy. So now that our request is ready for Pardot, we’re gonna fire it off saying, okay, Pardot. Send this email using this campaign to these people. We’ll check to see if the risk the API request was successful. And I’ve got a bunch of stuff here in the script for if you’re playing with it yourself, you can basically, it’s gonna force you to wait or ask you to wait before it goes and does the field cleanup. And we take this a similar approach with the batches. We don’t have to do as much calculations because we’ve actually kept track of each bucket that was filled up, and we can just loop through all of the batches, which are the each individual bucket. Then we can loop through each prospect, clear the clear the custom fields, and then we can update the batch. So I’m not gonna run this script again so that we don’t have to hang out too long together. So what does that look like in Pardot? Right. So Luminar has got a couple of emails sent. So what I’m gonna do is I’m going to refresh this Pardot prospect view, and we can see that we sent five listings. So because this email was sent, this was the one that was sent with the external template. Right? So when I gave the subject line to Pardot, it actually had the value, whereas this last email was sent using the um, Pardot email template, and for some reason, Pardot doesn’t actually want to fill in that placeholder, but that’s okay. So I think that wraps up the code demo. So let’s get back to here. So I think we have a couple of minutes for Q&A. Pam, do we have anything in the Q&A?

Speaker 0: I think you literally everyone’s minds with all of the details because they were not active in the chat. So I’m sure they’re just processing all of that great information.

Speaker 1: Either that or I put them all to sleep.

Speaker 0: No. I doubt it.

Speaker 1: Come on. Anyone in the chat? Anyone still awake? Still still watching here?

Speaker 0: We still have people in the session, so we we see you. Okay.

Speaker 1: So I wanna thank everyone for for showing up to this session, you know, late on a Friday. Um, you can reach me on LinkedIn or on Twitter. I tend to not post very much. So in the event that you choose to follow me, you’re not gonna get spammed with a whole bunch of garbage. If you don’t like social media, you know, just send me an email, and, uh, we can chat about this or any other questions you might have.

Speaker 0: Excellent. Thanks so much, Adam. Uh, we’ve got some, uh, some some comments coming in now. People are not asleep, and they love the presentation.

Speaker 1: They’re processing

Speaker 0: it all. So and just a reminder to everybody, this is recorded so you can come back and rewatch it, um, for further detail absorption.

Speaker 1: Yep. Recorded. The code is available for you. You can dive into some of the functions that I didn’t show on screen. Right? If you’re really curious and you wanna see how we logged in or you wanna see a bunch of things, it’s all in there.

Speaker 0: Awesome. Uh, thank you so much, Adam, and to everybody that attended the the session. And, of course, thank you to our sponsors that have, uh, made this event so fan fantastic. Okay. Thanks, everybody. Bye.