Email & Messaging
Limits: 10 sendEmail calls per transaction; daily limits for emails to external addresses (5,000 per org per day for single emails in most editions); emails are sent only if the transaction commits.
34.1 Sending email
Limits: 10 sendEmail calls per transaction; daily limits for emails to external addresses (5,000 per org per day for single emails in most editions); emails are sent only if the transaction commits. Attach files with Messaging.EmailFileAttachment or setEntityAttachments(contentVersionIds).
Messaging.reserveSingleEmailCapacity(2); // fail fast if daily limit would be exceeded
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new List<String>{ '[email protected]' });
mail.setCcAddresses(new List<String>{ '[email protected]' });
mail.setSubject('Your order has shipped');
mail.setHtmlBody('<p>Hello! Your order <b>A-1</b> is on its way.</p>');
mail.setPlainTextBody('Hello! Your order A-1 is on its way.');
mail.setOrgWideEmailAddressId(owaId); // send from a verified org-wide address
mail.setSaveAsActivity(false);
// template-based email (merge fields from a Contact/Lead/User + related record)
Messaging.SingleEmailMessage tmpl = new Messaging.SingleEmailMessage();
tmpl.setTemplateId(templateId);
tmpl.setTargetObjectId(contactId); // recipient + merge source
tmpl.setWhatId(orderId); // related record for merge fields
List<Messaging.SendEmailResult> results = Messaging.sendEmail(
new List<Messaging.SingleEmailMessage>{ mail, tmpl }, false); // allOrNone = false34.2 Inbound email services
Configure under *Setup → Email Services*: assign the class, accepted senders, and the context user; Salesforce generates an email address. (Email-to-Case is the no-code alternative for cases.)
global class SupportEmailHandler implements Messaging.InboundEmailHandler {
global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email,
Messaging.InboundEnvelope envelope) {
Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
try {
insert new Case(Subject = email.subject, Description = email.plainTextBody,
SuppliedEmail = email.fromAddress, Origin = 'Email');
result.success = true;
} catch (Exception e) {
result.success = false;
result.message = 'Could not create case: ' + e.getMessage();
}
return result;
}
}34.3 Custom and in-app notifications
Also: Chatter posts via ConnectApi.ChatterFeeds.postFeedElement or FeedItem DML, and Slack integration via Flow actions or the Slack Apex SDK (availability varies; check current docs).
CustomNotificationType type = [SELECT Id FROM CustomNotificationType WHERE DeveloperName = 'Deal_Alert' LIMIT 1];
Messaging.CustomNotification n = new Messaging.CustomNotification();
n.setNotificationTypeId(type.Id);
n.setTitle('Big deal closed');
n.setBody('Opportunity Acme Expansion closed for $1.2M');
n.setTargetId(oppId); // record to open on click
n.send(new Set<String>{ ownerId }); // user, group, or queue IDs