read custom metadata and send out emails
public class EmailToCaseNotifier {
public static void processFirstIncomingEmails(List<EmailMessage> newMessages) {
if (newMessages == null || newMessages.isEmpty()) return;
// Step 1: Identify cases
Set<Id> caseIds = new Set<Id>();
Map<Id, EmailMessage> firstMessages = new Map<Id, EmailMessage>(); // ParentId -> EmailMessage
for (EmailMessage em : newMessages) {
if (em.ParentId != null && em.Incoming) {
if (!firstMessages.containsKey(em.ParentId)) {
firstMessages.put(em.ParentId, em);
}
caseIds.add(em.ParentId);
}
}
if (caseIds.isEmpty()) return;
// Step 2: Filter to only those cases where this is the first incoming email
Map<Id, Integer> existingIncomingCounts = new Map<Id, Integer>();
for (AggregateResult ar : [
SELECT ParentId, COUNT(Id) cnt
FROM EmailMessage
WHERE ParentId IN :caseIds AND Incoming = true
GROUP BY ParentId
]) {
existingIncomingCounts.put((Id)ar.get('ParentId'), (Integer)ar.get('cnt'));
}
List<Id> eligibleCaseIds = new List<Id>();
for (Id caseId : caseIds) {
Integer count = existingIncomingCounts.get(caseId);
if (count == 1) {
eligibleCaseIds.add(caseId);
}
}
if (eligibleCaseIds.isEmpty()) return;
Map<Id, Case> caseMap = new Map<Id, Case>(
[SELECT Id, CaseNumber, RecordType.DeveloperName FROM Case WHERE Id IN :eligibleCaseIds]
);
// Step 3: Extract addresses from EmailMessages
Map<Id, Set<String>> caseIdToMatchedEmails = new Map<Id, Set<String>>();
for (Id caseId : eligibleCaseIds) {
EmailMessage em = firstMessages.get(caseId);
if (em == null) continue;
Set<String> addresses = new Set<String>();
for (String addr : new List<String>{ em.ToAddress, em.CcAddress }) {
if (addr != null) {
for (String e : addr.split(',')) {
String email = e.trim().toLowerCase();
if (!String.isBlank(email)) {
addresses.add(email);
}
}
}
}
if (!addresses.isEmpty()) {
caseIdToMatchedEmails.put(caseId, addresses);
}
}
// Step 4: Load metadata
Map<String, EmailToCaseMetadata__mdt> metadataByEmail = new Map<String, EmailToCaseMetadata__mdt>();
Set<String> templateNames = new Set<String>();
Set<String> potentialQueueNames = new Set<String>();
for (EmailToCaseMetadata__mdt meta : [
SELECT Email__c, Priority__c, CaseNotCreatedSendEmail__c,
CaseNotCreatedSendEmailTo__c, CaseNotCreatedEmailTemplate__c,
Case_Record_Type_Api_Name__c
FROM EmailToCaseMetadata__mdt
]) {
metadataByEmail.put(meta.Email__c.toLowerCase(), meta);
if (!String.isBlank(meta.CaseNotCreatedSendEmailTo__c) &&
!meta.CaseNotCreatedSendEmailTo__c.contains('@')) {
potentialQueueNames.add(meta.CaseNotCreatedSendEmailTo__c);
}
if (!String.isBlank(meta.CaseNotCreatedEmailTemplate__c)) {
templateNames.add(meta.CaseNotCreatedEmailTemplate__c);
}
}
// Step 5: Email templates
Map<String, Id> templateNameToId = new Map<String, Id>();
for (EmailTemplate tmpl : [
SELECT Id, DeveloperName FROM EmailTemplate WHERE DeveloperName IN :templateNames
]) {
templateNameToId.put(tmpl.DeveloperName, tmpl.Id);
}
// Step 6: Queues and users
Map<String, Id> queueNameToId = new Map<String, Id>();
for (Group g : [
SELECT Id, Name FROM Group WHERE Name IN :potentialQueueNames AND Type = 'Queue'
]) {
queueNameToId.put(g.Name, g.Id);
}
Map<String, List<String>> queueNameToEmails = new Map<String, List<String>>();
if (!queueNameToId.isEmpty()) {
Map<Id, List<Id>> groupIdToUserIds = new Map<Id, List<Id>>();
for (GroupMember gm : [
SELECT GroupId, UserOrGroupId FROM GroupMember WHERE GroupId IN :queueNameToId.values()
]) {
if (!groupIdToUserIds.containsKey(gm.GroupId)) {
groupIdToUserIds.put(gm.GroupId, new List<Id>());
}
groupIdToUserIds.get(gm.GroupId).add(gm.UserOrGroupId);
}
Set<Id> userIds = new Set<Id>();
for (List<Id> ids : groupIdToUserIds.values()) userIds.addAll(ids);
Map<Id, String> userIdToEmail = new Map<Id, String>();
for (User u : [SELECT Id, Email FROM User WHERE Id IN :userIds]) {
userIdToEmail.put(u.Id, u.Email);
}
for (String queueName : queueNameToId.keySet()) {
List<Id> uids = groupIdToUserIds.get(queueNameToId.get(queueName));
List<String> emails = new List<String>();
if (uids != null) {
for (Id uid : uids) {
if (userIdToEmail.containsKey(uid)) {
emails.add(userIdToEmail.get(uid));
}
}
}
queueNameToEmails.put(queueName, emails);
}
}
// Step 7: Send notifications
List<Messaging.SingleEmailMessage> emailsToSend = new List<Messaging.SingleEmailMessage>();
for (Id caseId : eligibleCaseIds) {
Case c = caseMap.get(caseId);
if (c == null) continue;
Set<String> matchedEmails = caseIdToMatchedEmails.get(caseId);
if (matchedEmails == null || matchedEmails.isEmpty()) continue;
for (String email : matchedEmails) {
EmailToCaseMetadata__mdt meta = metadataByEmail.get(email);
if (meta == null || !meta.CaseNotCreatedSendEmail__c) continue;
if (String.isBlank(meta.Case_Record_Type_Api_Name__c)) continue;
if (meta.Case_Record_Type_Api_Name__c == c.RecordType.DeveloperName) continue;
List<String> recipients = new List<String>();
String toField = meta.CaseNotCreatedSendEmailTo__c;
if (!String.isBlank(toField)) {
if (toField.contains('@')) {
recipients.add(toField);
} else if (queueNameToEmails.containsKey(toField)) {
recipients.addAll(queueNameToEmails.get(toField));
}
}
if (recipients.isEmpty()) continue;
Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
msg.setToAddresses(recipients);
msg.setTargetObjectId(UserInfo.getUserId());
msg.setWhatId(c.Id);
if (!String.isBlank(meta.CaseNotCreatedEmailTemplate__c) &&
templateNameToId.containsKey(meta.CaseNotCreatedEmailTemplate__c)) {
msg.setTemplateId(templateNameToId.get(meta.CaseNotCreatedEmailTemplate__c));
} else {
msg.setSubject('Missed Case Notification for ' + email);
msg.setPlainTextBody('A case was created, but not using the expected record type "' +
meta.Case_Record_Type_Api_Name__c + '" for email: ' + email +
'. Please review case ' + c.CaseNumber);
}
emailsToSend.add(msg);
}
}
if (!emailsToSend.isEmpty()) {
Messaging.sendEmail(emailsToSend);
}
}
}
read custom metadata and send out emails
Reviewed by dasfrogpractice
on
05:50
Rating:
No comments: