Failure to send email causing a database rollback

I’m having a strange issue within Salesforce. I am trying to create an object and send an email about it on the finish() command on a “Database.Batchable, Database.AllowsCallouts, Database.Stateful“.

What happens is when I try to send the email I get these two errors:

EXCEPTION_THROWN|System.EmailException: SendEmail failed. First
exception on row 0; first error: INVALID_CROSS_REFERENCE_KEY, invalid cross reference id:[]

EXCEPTION_THROWN|System.UnexpectedException:
Programmer error: cannot rollback to savepoint on another transaction

This rollbacks to before the object was saved (up until I try to send the email I can system.debug() the variable, it does exist and is queryable.

I even added in a Database.setSavepoint(); before the attempt to send an email. Didn’t make a difference.

What hidden obscure rule of Salesforce am I breaking to cause this issue?

NOTE:

  • If I do not try to send the email it works completely fine, and I know Salesforce can send emails in Database.Batchable because A) It’s in their example, B) I have other Batchables sending emails.

Code:

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();


            mail.setTargetObjectId(contact.Id);
            system.debug(mail.getTargetObjectId()); // Has value
            mail.setWhatId(invoice.Id);
            system.debug(mail.getWhatId());// Has Value
            mail.setTemplateId(et.Id);
            system.debug(mail.getTemplateId()); // Has Value


            OrgWideEmailAddress[] owea = [select Id from OrgWideEmailAddress where DisplayName =:associate.Name AND IsAllowAllProfiles = true];

            system.debug(owea); // Has value

            if ( owea.size() > 0 ) {
                //mail.setOrgWideEmailAddressId(owea.get(0).Id);
                mail.setSenderDisplayName(associate.Name);
                mail.setReplyTo(associate.Email__c);
            }else{
                mail.setSenderDisplayName(associate.Name);
                mail.setReplyTo(associate.Email__c);
            }



            try{
                Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});// <---- Breaks here
            }catch(Exception e){

            }
            invoice.Email_Sent__c = true;
            update invoice;

UPDATE: It appears to be a problem only with attaching as PDF within the Visualforce Template (this template I’ve used in a variety of contexts, future, direct email, etc without issue [Including the attaching as PDF function ])

Visualforce template:

<messaging:htmlEmailBody >
    <!-- Sends email fine when this is within body -->
    <c:Invoice_PDF_HTML_Content invoice_id="{!relatedTo.Id}" />
</messaging:htmlEmailBody>

<messaging:attachment renderAs="pdf" filename="Invoice.pdf">
     <!-- Stops sending when within the attachment tag -->
    <c:Invoice_PDF_HTML_Content invoice_id="{!relatedTo.Id}" />
</messaging:attachment>

Invoice_PDF_HTML_Content VF:

<apex:component access="global" controller="Invoice_Quote_Controller" >

    <apex:attribute access="public" name="invoice_id" description="Invoice ID" type="String" assignto="{!InvoiceId}"/>

    <table border="0" cellspacing="0" cellpadding="0" width="100%" id="table1" face="Arial" style="font-family: Arial;">
<!-- More HTML with little Apex, just OutputField's -->
</apex:component>

Controller:

global without sharing class Invoice_Quote_Controller {

    public List<Prospective_Custom_Charge__c> custom_charges {get;set;}
    public List<Prospective_Product__c> product_charges {get;set;}

    public List<Invoice_Line__c> line_items {get;set;}

    public Associate__c associate {get;set;}
    public String email_header {get;set;}
    public Date todays_date {get;set;}
    public String invoice_date {get;set;}
    public Double sub_total {get;set;}

    public PageReference page_reference;


    private String invoiceId = null;

    public Invoice__c invoice {get;set;}

    private Id account_id; 
    private Id assoc_id;


    public String getInvoiceID(){
        system.debug(invoiceId);
        return invoiceId;
    }

    public void setInvoiceID(String InvoiceId){
        this.invoiceId = InvoiceId;
        system.debug(InvoiceId);

        invoice = [SELECT Id,CreatedDate,Name,Account__c,Account__r.Name,Account__r.BillingStreet,Account__r.BillingPostalCode,Account__r.BillingCity,Billing_Frequency__c,GST__c,Payment_Method__c,Total__c FROM Invoice__c WHERE Id=:invoiceId];


        account_id = invoice.Account__c;
        Account acc = [SELECT Associate__c FROM Account WHERE Id=:account_id];
        assoc_id = acc.Associate__c;




    todays_date = Date.today();


    Datetime inv_date = invoice.CreatedDate;
    invoice_date = inv_date.format('MMMM d,  yyyy');

    line_items = [
        SELECT Id, Amount__c, Description__c, Invoice__c, Product_Name__c, Quantity__c
        FROM Invoice_Line__c
        WHERE Invoice__c=:invoiceId
    ];

    associate = [
        SELECT Id,Name, Phone__c, Email__c, Email_Header__c
        FROM Associate__c
        WHERE Id=:assoc_id
    ];

    email_header = associate.Email_Header__c;

    sub_total = invoice.Total__c - invoice.GST__c;
}

}


UPDATE 2: After commenting out individual lines, I’ve found the culprit (the single two lines that allow the email to send or not):

Controller:

email_header = associate.Email_Header__c;

VF:

<apex:outputText value="{!email_header}" escape="false" />

Commenting out either line will allow the email to send without error. associate.Email_Header__c is a Rich Text Box (salesforce data type), has an image within it and text.
Example:

 <img alt="Companu Logo" src="http://assist.company.com.au/api/public/img/associates/email_logo/company.gif"> <p>Company Phone Number</p>

UPDATE 3:
When I remove the < img > tag it works fine, should I report this as a bug to Salesforce at this stage?

UPDATE 4: If I upload the image to Salesforce it works in the PDF (but gives a 404 error in the email, for obvious reasons). If I use a remote host, it gives the invalid cross reference id, cannot rollback to savepoint….

Answer

The problem turned out to be when an < img > tag had a remote url instead of an internal Salesforce one (from what I could see, it made no difference if it was an allow remote point, http or https). The solution was to remove any external facing url’s from < img >’s, I setup two fields on the objects one for the internal image (for PDF processing) and an external image (for viewing in the email). This is a workaround at best and doesn’t solve (or reveal?) the real issue.

I’m putting this answer down as this worked, but, I won’t be marking it as best answer because it doesn’t actually solve the issue.

NOTE: If you used an image outside of a validated remote site it would work, but give an “image not found” image in the PDF (but it wouldn’t crash), once you validate the remote site, it would then crash.

Attribution
Source : Link , Question Author : Mattisdada , Answer Author : Mattisdada

Leave a Comment