function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Matthew HofmannMatthew Hofmann 

Apex InvocableMethod - INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY error

Hello all,

I have created an Apex class with an InvocableMethod that logs automated outgoing emails as EmailMessage records. The InvocableMethod is called by process builder whenever the process also uses an email alert action. It works very well for myself and other Full Salesforce licesed users. However, when a user with a Customer Community Plus license makes a change to a case which triggers the process, the process fails with an "INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY" error.

Salesforce support said that the EmailMessage object is off-limits to this type of license, however the object is available for the user's profile for field-level security. Also this article says that Customer Community Plus licenses have Send Email capability: https://help.salesforce.com/articleView?id=users_license_types_communities.htm&type=5

Has anyone had experience with this or something similar in the past?
Matthew HofmannMatthew Hofmann
Here is the error message received from process builder (flow error):

Error element myRule_1_A2 (FlowActionCall).
An Apex error occurred: System.DmlException: Insert failed. First exception on row 0; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: [] 
This report lists the elements that the flow interview executed. The report is a beta feature.
We welcome your feedback on IdeaExchange.
Flow Details
Flow Name: Case_Automated_Emails
Type: Workflow
Version: 1
Status: Active
Flow Interview Details
Interview Label: Case_Automated_Emails-1_InterviewLabel
Current User: Test Tech (00529000001RRVZ)
Start time: 12/20/2017 7:04 AM
Duration: 0 seconds
How the Interview Started
Test Tech (00529000001RRVZ) started the flow interview.
Some of this flow's variables were set when the interview started.
myVariable_old = 50029000005RIioAAG
myVariable_current = 50029000005RIioAAG
ASSIGNMENT: myVariable_waitStartTimeAssignment
{!myVariable_waitStartTimeVariable} Equals {!Flow.CurrentDateTime}
Result
{!myVariable_waitStartTimeVariable} = "12/20/2017 7:04 AM"
DECISION: myDecision
Executed this outcome: myRule_1
Outcome conditions: and
1. {!myVariable_current.Status} (Tech Scheduled) Equals Tech Scheduled
Logic: All conditions must be true (AND)
DECISION: myRule_1_pmetdec
CASE.SEND_TECHNICIAN_IS_SCHEDULED_COMMUNICATION_CONSUMER (EMAIL ALERTS): myRule_1_A1
Inputs:
SObjectRowId = {!myVariable_current.Id} (50029000005RIioAAG)
Outputs:
None.
EMAILMESSAGEINSERTACTION (APEX): myRule_1_A2
Inputs:
emailTemplateId = 00XF0000000kICN
fromEmailAddress = redated@outboundemail.address
parentCaseId = {!myVariable_current.Id} (50029000005RIioAAG)
toEmailAddress = {!myVariable_current.Contact.Email} (redacted@redacted.redacted)
Error Occurred: An Apex error occurred: System.DmlException: Insert failed. First exception on row 0; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: [] 
Salesforce Error ID: 1854753996-32887 (1243982501)
Matthew HofmannMatthew Hofmann
Here is the Apex code:
 
global without sharing class EmailMessageInsertAction {
  @InvocableMethod(label='Insert Email Message')
  global static void insertEmailMessages(List<InsertEmailMessageActionRequest> requests) {
    for (InsertEmailMessageActionRequest request : requests) {
      insertEmailMessage(request);
    }
  }

  public static void insertEmailMessage(InsertEmailMessageActionRequest request) {
	//get merged template info
	Messaging.SingleEmailMessage emailMsg = Messaging.renderStoredEmailTemplate(request.emailTemplateId, request.toId, request.parentCaseId);
	//create email message
      EmailMessage eMsg = new EmailMessage();
      System.Debug('message');
      eMsg.fromAddress = request.fromEmailAddress;
      eMsg.parentId = request.parentCaseId;
      eMsg.status = '3';
      eMsg.subject = emailMsg.getSubject();
      eMsg.textBody = emailMsg.getPlainTextBody();
      eMsg.htmlBody = emailMsg.getHTMLBody();
      eMsg.ToAddress = request.toEmailAddress;

	//insert email message
      insert eMsg;
  }

  global class InsertEmailMessageActionRequest {
    @InvocableVariable(required=true)
    global ID parentCaseId;

    @InvocableVariable(required=true)
    global String emailTemplateId;
      
    @InvocableVariable(required=true)
    global String fromEmailAddress;
      
    @InvocableVariable(required=true)
    global String toEmailAddress;
      
	@InvocableVariable//(required=true)
    global String toId;
  }
}

And test code in case you are curious:
 
@isTest
public class EmailInsertActionTest {
    static testMethod void doTest() {
        
        User thisUser = [ select Id from User where Id =: UserInfo.getUserId()];
        System.runAs(thisUser) {
            EmailTemplate testEmailTemplate = new EmailTemplate(IsActive=TRUE,
                                                               Encoding='ISO-8859-1',
                                                               FolderId=UserInfo.getUserId(), //running user's personal folder
                                                               Name='Test Email Template',
                                                               DeveloperName='Test_Email_Template',
                                                               Subject='Test Email Template Subject',
                                                               Body='Test Email Template Body',
                                                               TemplateType='Text');
            insert testEmailTemplate;
    	}
        
        Test.startTest();
        
        Account testGPSPartner = new Account(Name='Test GPS Partner',
                                             Active__c=TRUE,
                                            Industry='Retailer');
        insert testGPSPartner;
        
        Contact testTech = new Contact(FirstName = 'Test',
                                  LastName = 'Tech',
                                  MailingPostalCode='49512');
        insert testTech;
        
        Contact testConsumer = new Contact(FirstName='Test',
                                          LastName='Consumer',
                                          MailingPostalCode='48838');
        insert testConsumer;
        
        Case testCase = new Case(Subject='Test Subject',
                                Account=testGPSPartner);
        insert testCase;
        
        EmailTemplate testEmailTemplate = [SELECT IsActive, Encoding, FolderId, Name, DeveloperName, Subject, Body, TemplateType FROM EmailTemplate WHERE DeveloperName = 'Test_Email_Template'];
        
        EmailMessageInsertAction.InsertEmailMessageActionRequest iemar = new EmailMessageInsertAction.InsertEmailMessageActionRequest();
        iemar.parentCaseId=testCase.Id;
        iemar.emailTemplateId=testEmailTemplate.Id;
        iemar.fromEmailAddress='from@email.address';
        iemar.toEmailaddress='to@email.address';
        
        //EmailMessageInsertAction.InsertEmailMessageActionRequest iemar = new EmailMessageInsertAction.InsertEmailMessageActionRequest();
            
        EmailMessageInsertAction.insertEmailMessages(New EmailMessageInsertAction.InsertEmailMessageActionRequest[]{iemar});
        
        Test.stopTest();
        
        EmailMessage resultantEmailMessage = [SELECT ParentId, Subject, TextBody, FromAddress, ToAddress, Status FROM EmailMessage WHERE ParentId =: testCase.Id];

        System.assertEquals(resultantEmailMessage.ParentId, testCase.Id);
        System.assertEquals(resultantEmailMessage.Subject, testEmailTemplate.Subject);
        System.assertEquals(resultantEmailMessage.TextBody, testEmailTemplate.Body);
        System.assertEquals(resultantEmailMessage.FromAddress, iemar.fromEmailAddress);
        System.assertEquals(resultantEmailMessage.ToAddress, iemar.toEmailaddress);
        System.assertEquals(resultantEmailMessage.Status, '3');
        //System.assertEquals(resultantEmailMessage.Incoming, FALSE);
    }
}