I am building a typical help site where there are a lot of unauthenticated pages that the user can view like product catalog, help guides ...etc and couple of authenticated pages (My Cases, Case View). The Case View page allows the user to view the latest email on the case and provides a textarea where they can enter any information. Due to an existing design, whatever is entered should be stored in the EmailMessage object linked to the Case.

When I insert a new record into EmailMessage object, I get an error saying Insert failed. First exception on row 0; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: []

Interestingly, I have an unauthenticated page that allows anyone browsing the website to create a case and that piece of code also inserts into EmailMessage object. The unauthenticated page inserts without any errors. So I couldn't help but wonder why an authenticated page gets the insufficient access error. Any insights would help. Here is a much trimmed down version of the page and class where the error is replicable.

I have checked the usual suspects - Object access, FLS, Page access. I am able to update the case but it is the EmailMessage that am not able to insert.

public class PortalCaseView {

    public PortalCaseView(){ }

    public void insertMsg(){
        EmailMessage msg = new EmailMessage(
            FromAddress = 'aaa@bbb.com',
            FromName = 'Stackoverflow',
            Subject = 'Problem',
            TextBody = 'Description about the problem',
            ParentId = '500e00000036va1',
            Incoming = true,
            Status = '0'
        insert msg;


VF Page

<apex:page controller="PortalCaseView">
    <apex:form >
        <apex:commandButton action="{!insertMsg}" value="Insert" />
  • why are you hardcoding the case or whatever 500e00000036va1 this id is for the parent Id? – Rao Jul 17 '14 at 22:06
  • @rao I trimmed down the actual code to just the part where the error happens. Hardcoded the case id for testing purpose. – DCBoy Jul 18 '14 at 2:03
  • Check whether you are restricting access to the owner of the record. – highfive Jul 18 '14 at 3:34


Customer Portal users have read access to this object.

So it's right there in the docs. Not renamed from "portals" to "communities" but still.

You might have to hack the hell out of it to use the form from unauthenticated page. Couple ideas:

  • embed it as iframe?
  • use regular html <form action="/unauthCaseComment"> instead of apex:form? It would serve as some kind of redirect, on the new page you read the URL variables and insert?)
  • or even better without going through URL - check if you can reuse same controller / same std. controller extension on both

I've went other way around in the past and I store content of inbound emails as Case Comments. Task would do too I guess. This might be a huge shift for you (I understand that you have lots of reports etc that rely on EmailMessage)...

  • I did see the help doc, what threw me off was that I was able to insert into EmailMessage as an unauthenticated user but not as an authenticated. Ended up exposing a REST service to which I POST a request to create a email record. Added a bunch of authentication keys to ensure that no one else can submit emails just with the case Id. – DCBoy Jul 22 '14 at 4:16
  • add your own answer then if you're willing to share the code :) – eyescream Jul 22 '14 at 5:53

EmailMessage records cannot be inserted from Authenticated pages while it can be done from Unauthenticated pages. See help link from @eyescream's comment. As a workaround, I created an Apex REST service and exposed it via Unauthenticated Site.

global class EmailInsert {

    global static String addEmail(String p_FromName,
                                    String p_FromEmail,
                                    String p_ToAddress,
                                    String p_Subject,
                                    String p_TextBody,
                                    String p_HTMLBody,
                                    String p_CaseId) {

        EmailMessage msg = new EmailMessage(
            FromName        = p_FromName,
            FromAddress     = p_FromEmail,
            ToAddress       = p_ToAddress,
            Subject         = p_Subject,
            TextBody        = p_TextBody,
            HtmlBody        = p_HTMLBody,
            ParentId        = p_CaseId,

            MessageDate     = System.now(),
            Incoming        = true,
            Status          = '0'
        insert msg;

        return msg.Id;

--- You can invoke this from your class as follows, code has been trimmed for clarity

    String jsonInput = '{';
    jsonInput +=            '"p_FromName":"' + FromName + '",';
    jsonInput +=            '"p_FromEmail":"' + FromAddress + '",';
    jsonInput +=            '"p_ToAddress":"' + ToAddress + '",';
    jsonInput +=            '"p_Subject":"' + Subject + '",';
    jsonInput +=            '"p_TextBody":"' + TextBody  + '",';
    jsonInput +=            '"p_HTMLBody":"",';
    jsonInput +=            '"p_CaseId":"' + ParentId + '"';
    jsonInput +=        '}';

    // Call the web service to insert into Email Message object
    Http http       = new Http();
    HttpRequest req = new HttpRequest();

    req.setEndpoint('https://<site page>/services/apexrest/emailservices');


--- Remember to add the class to the unauthenticated site's profile.


I had a similar issue where we used a custom object to capture information and would then create an EmailMessage FeedItem on the associated Case. I couldn't get the REST API to work but perhaps I'm just not as familiar with it.

As a workaround we took all the information that needed to be put into the email message and used a workflow to send an outbound email to the email-to-case service address which subsequently creates an EmailMessage.

Just get all your information into the email template, be sure to include the Case Thread_ID for proper routing: https://success.salesforce.com/ideaView?id=08730000000XvdHAAS

It's not the most elegant solution but it works pretty seamlessly for us until we can figure out another solution.


When does this error happen? This error normally happens when a DML operation is performed. Meaning that, whenever an Insert or Update is performed. You won't see this error when you save your APEX class or TRIGGER, because this error happens at RUNTIME.

What does this error mean? This error means that you are trying to do an operation which is not supposed to be done, or the operation you are about to perform is not permitted according to the Sharing and Security settings defined. This error message does NOT always mean that you lack access to do the operation, even though it might be the case sometimes. So, even if you are an ADMINISTRATOR you may get this message.

Scenario 1: Creating a new record (Account/Contact/...) and setting the Owner. Applies to updating records as well.

So, in your code you create some records. By Default the creator of the record is the Owner. You want to change this and you modify the OwnerId column of the newly created records. You make "User X" as the Owner. Now when you run the code, you get the Error below: System.DmlException: Insert failed. First exception on row 2; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: []

Things to check: *Check that the running user (in this case you) has access to the object being operated. Check that he has CREATE privileges on the object. This is optional, but is always better to start from here. *Check that the Owner ie User X has CREATE permission on the object. Check that his profile has the CREATE permission on the particular object. He might not be having it, grant him permission and the issue is resolved.

Scenario 2: Creating or Updating an Opportunity (just for an example, might be any object). Setting the related Account of the Opportunity.

So, let's say that you create 5 Opportunities and you set the Owner to "User X". You set the Account to "Account X". When your code tries to insert these 5 opportunities, it fails and you get the same error message. System.DmlException: Insert failed. First exception on row 2; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: [] Reason: This is because "User X" does not have access to "Account X". When you try to create an Opportunity for "Account X" that he does not have access to the code fails. Either grant access to "User X" for "Account X" manually or through code and then do the Insert.

Scenario 3: The Sharing Object.

This is a bit complex to get at. atleast for me. You might be aware that every object has its own Share object. So, Account has AccountShare and Customobj__c has Customobj__Share When you insert or update records in this object you might receive the same error message. There are a number of reasons for this to happen.

*If you are trying to share "Record X" with "User Y" and "User Y" does not have access to the object (the profile level permission, create read edit delete), this error happens.
*If you are trying to share "Record X" with "User Y" and "User Y" already has access to "Record X" this error happens.

please check this once before u do i think it will surely help u.

Your Answer

