“SMS-to-Lead?”, you ask? Well, as you probably know, Web-to-Lead is a core feature of the Force.com platform, allowing you to create Lead records directly from a form on your website, a cornerstone of CRM functionality. In a recent blog post, Sandeep combined Facebook, Heroku and Force.com to create Social Web-to-Lead. That, together with Twilio’s release of their library for Salesforce, got me thinking about SMS-to-Lead.
The base concept is very simple – run a campaign inviting prospective customers to text their email address to find out more about your product, receive some freebie, whatever. It turns out that the execution is almost as simple as the concept. Today I’ll walk you an Apex class that does exactly that, in less than 100 lines. (Here’s the code in its entirety).
First, I define the class, with a
@RestResource annotation. This is a RESTful web service that will be deployed at the relative URL
I’ve already installed the Twilio library and configured a custom setting with my Twilio account credentials, so I can get a reference to my Twilio account by just calling
Now I define a method that will accept an HTTP POST from Twilio:
I’ll be sending an email, so I reserve capacity up front to do so. This ensures that, if I’ve already reached my daily email limit, an error will be thrown before any more processing is done.
Having done that, since this is a web service deployed at a public endpoint, it’s important to verify that this POST really did come from Twilio. I do that by gathering the signature passed in via the
X-Twilio-Signature header, the requested URL, and request parameters, and passing them to the
validateRequest() method in the
TwilioRestClient class. validateRequest() calculates an HMAC of the request data, using my Twilio auth token as the key (the auth token is a secret that I share with Twilio), and comparing it to the signature sent in the request. If the calculated HMAC matches the signature from the header, I can be confident that this request came from Twilio and it was not modified in transit. I’m setting the response body in the sample to aid debugging, but, in production, you would return the 403 status with no body.
Now I’ve validated the signature, I set up a response, since Twilio will log a 502 error if I respond with HTTP status 200, but no body.
That out of the way, I can pull data out of the request parameters:
I’ve added a custom field to the Campaign object so I can automatically associate the incoming SMS with a marketing campaign I’m running. Here I use the phone number from the SMS to locate the Campaign record. If there is no matching campaign, I send an SMS reply with an error (see below for the reply method). You would only expect to see this error in early testing, if a Campaign record had not been created, or was configured with the wrong number.
Now I have the Campaign, I insert a Lead. Note that Leads are not directly associated with a Campaign – I’ll need to create a CampaignMember record later. I set the Lead’s LastName and Company to ‘From SMS’, since these are required fields but I don’t have real data to put there. In a real marketing campaign, these would likely be updated later on as the sales team engages with the lead.
I don’t bother doing any validation on the email address from the SMS, since the platform will do that for me when I insert it, throwing a
DmlException if the value in the
Now I can link the Lead to the Campaign.
I send an SMS reply to thank the texter:
Let’s take a look at the
reply() method that I define further down in the
SmsToLead class. I need that
@future annotation since sending an SMS invokes a callout to Twilio, and I can’t execute a synchronous callout, since I’ve made changes to the database that are not yet committed.
@future solves the problem by making calls to
reply() asynchronous – they go on a queue and are executed shortly afterward.
With all that done, all that remains is to send the texter an email. In a real campaign, I’d likely include a link, allowing the user to opt in to the campaign and provide more of their details. Here I send a simple acknowledgment. Using
setTargetObjectId(), rather than
setToAddresses(), allows the platform to record this email as an activity against the Lead. This is the default behavior when you specify a Lead, Contact or User Id this way, but I call
setSaveAsActivity() to make it explicit in the code.
With the Twilio library installed and configured, and the
SmsToLead class in place, you’ll need to configure a site and follow the instructions here to set up a publicly accessible endpoint of the form
https://somesite.force.com/services/apexrest/smstolead. Create a phone number at Twilio, and set your new endpoint as its SMS Request URL:
You should be able to text your email address to the Twilio number, and see a new Lead in your org, complete with an email address, phone number, an email in its activity history and a campaign listed:
So, there you have it – SMS-to-Lead. How are you acquiring leads in your org? Share your experience in the comments…