Sending Emails in Salesforce to Non-Contacts Using Apex
Why won’t the following code work? (Assume that there is an active email template with the given name.)
List<Messaging.SingleEmailMessage> lstMsgs =
new List<Messaging.SingleEmailMessage>();
Messaging.SingleEmailMessage msg =
new Messaging.SingleEmailMessage();
msg.setTemplateId( [select id from EmailTemplate
where DeveloperName='My_Email_Template'].id );
msg.setWhatId( [select id from Account limit 1].id );
msg.setTargetObjectId(UserInfo.getUserId());
lstMsgs.add(msg);
Messaging.sendEmail(lstMsgs);
Did you find the problem? If not, try running it yourself, substituting your own Email Template name. You’ll get this error:WhatID is not available for sending emails to UserIds
The problem is that if you specify a TargetObjectId (the record from which the Email Template will probably draw most of its merge fields), Apex’s Messaging classes require you to specify a WhatID that refers to a Contact, not a User.
But what if you don’t want to send your email to a Contact? What if you want to use an Email Template with a TargetObjectId to send an email to a User? Or to an email address that isn’t associated with a Contact or a User? Are you out of luck?
With a little magical Apex hand-waving, you can indeed send your email just the way you want to.
Consider this code:
1 // Pick a dummy Contact
2 Contact c = [select id, Email from Contact where email <> null limit 1];
3
4 // Construct the list of emails we want to send
5 List<Messaging.SingleEmailMessage> lstMsgs = new List<Messaging.SingleEmailMessage>();
6
7 Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
8 msg.setTemplateId( [select id from EmailTemplate where DeveloperName='My_Email_Template'].id );
9 msg.setWhatId( [select id from Account limit 1].id );
10 msg.setTargetObjectId(c.id);
11 msg.setToAddresses(new List<String>{'random_address@opfocus.com'});
12
13 lstMsgs.add(msg);
14
15 // Send the emails in a transaction, then roll it back
16 Savepoint sp = Database.setSavepoint();
17 Messaging.sendEmail(lstMsgs);
18 Database.rollback(sp);
19
20 // For each SingleEmailMessage that was just populated by the sendEmail() method, copy its
21 // contents to a new SingleEmailMessage. Then send those new messages.
22 List<Messaging.SingleEmailMessage> lstMsgsToSend = new List<Messaging.SingleEmailMessage>();
23 for (Messaging.SingleEmailMessage email : lstMsgs) {
24 Messaging.SingleEmailMessage emailToSend = new Messaging.SingleEmailMessage();
25 emailToSend.setToAddresses(email.getToAddresses());
26 emailToSend.setPlainTextBody(email.getPlainTextBody());
27 emailToSend.setHTMLBody(email.getHTMLBody());
28 emailToSend.setSubject(email.getSubject());
29 lstMsgsToSend.add(emailToSend);
30 }
31 Messaging.sendEmail(lstMsgsToSend);
In lines 1-14, we begin by constructing an email message using a WhatID that refers to some random Contact. As long as our email template doesn’t use “recipient” merge fields, it doesn’t matter which Contact we pick: we’re never going to actually send the email message to that Contact.
In lines 16-18, we set a savepoint, send the email, and then roll back the transaction. The key here is to understand that Salesforce doesn’t send an email immediately when the sendEmail method is executed. Instead, Salesforce waits until the very end of the transaction. If you roll back the transaction, Salesforce doesn’t send the email at all.
If sendEmail doesn’t actually send the email message, why bother calling it? Because when you call sendEmail, Salesforce populates the email message’s Subject, Body, PlainTextBody, and HTMLBody based on the Email Template, TargetObjectId, and What ID. When you roll back the transaction, Salesforce retains the populated values in the Subject, Body, and other fields. So after you roll back the transaction, you can construct a new SingleEmailMessage, and copy the Subject, Body, and other values from the populated message into the new message. Your new message is able to leverage the work that the email template did, but because your new message doesn’t refer to the email template, you don’t have to provide the emailTemplateId, TargetObjectId or WhatID, and you’re no longer bound by the requirement to specify a Contact for the WhatID. You can send your email to whomever you want, leveraging a Subject and Body that were created by an Email Template.
This trick of rolling back transactions can be useful in other ways as well. Last year, I wrote about how you can create Opportunity Assignment Rules by rolling back transactions in conjunction with Lead Assignment rules. What other uses can you find for rolling back transactions?
If your team is overwhelmed or you’re looking to fast track your upcoming projects, our team of consultants is here to help. Connect with a member of our team to discuss your project, then access a deep bench of Salesforce consultants to meet your needs. Are you ready to reach for operational excellence?