In a @Future method (because of other MIXED_DML problems) we are upserting users and collecting the results. We then want to send an email once the transaction is complete.
If everything works well, then the users are upserted and the email is sent.
However, if there is a Database error, then the email is not sent with the following error:

MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): EmailMessage, original object: User: [].  


List<Database.UpsertResult> userResults;
    userResults = Database.upsert(userList, User.Fields.Username, false);
    //if (Utils.isValidEmail(emailAddress)){
    //  sendEmail(emailAddress, userResults);
catch(Exception e){

So here's the thing. If we cause the one of the users to fail on the upsert, then we don't get to the catch block. The System.debug on line 4 prints the UpsertResult array, and we see that one failed and the rest succeeded.
But if we uncomment lines 5-7 then the catch block is activated and we see the ERROR debug lines. And that's were we see the MIXED_DML error with the email.
So, when everything works it can upsert users and send emails in the same transaction (only not really since it's an email queue). But if one of the records fails, the UpsertResult catches it no problem, but it can't push a SingleEmailMessage to the queue because of MIXED_DML.

  • 2
    Do you ever setSaveAsActivity(false)?
    – Adrian Larson
    Commented Feb 17, 2019 at 9:09
  • Yeah, that worked. Even though there is no reason why it should. There is no targetObjectId for the recipientList, just a plaintext email address. Answer the question and I'll accept your answer. Commented Feb 17, 2019 at 9:33
  • if using allOrNone=false; you should avoid the try-catch around the upsert as it will not throw an exception (assuming userList is non-null). Instead, inspect (by looping through userResults) to see which record(s) failed and take appropriate action
    – cropredy
    Commented Feb 18, 2019 at 5:03
  • @cropredy Yes, I know. The try/catch is there to catch the email send error, not the upsert error. Commented Feb 18, 2019 at 9:02

1 Answer 1


Make sure you call setSaveAsActivity(false) in your sendEmail method to avoid having it create any records.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .