I spend a lot of time on identity and integration, but I recently got back to salesforce.com’s roots in sales force automation and customer relationship management with some work on SMS-to-Lead.
“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 /smstolead
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 TwilioAPI.getDefaultAccount()
:
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 Email
field does not appear to be a valid email address. Note that well-formatted but non-existent email addresses will be accepted, so you might want to use a service such as StrikeIron’s Email Verification in a real production setting.
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.
Download the full source code here.
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…