I am currently recreating much of the OOB Quote functionality in Apex and I am almost complete. Now there is just one other hurdle, the Email Quote functionality.

Now, it doesn't seem like an issue.... at first.

I am able to create a QuoteDocument, set it up as an attachment, setup my email message with a template, and even create a task for the email being sent. However, as soon as I set the WhatId using the setWhatId method, I get the following error:

System.EmailException: SendEmail failed. First exception on row 0; first error: INVALID_ID_FIELD, Only accounts, assets, campaigns, cases, contracts, opportunities, orders, products, solutions and custom objects are allowed as whatId.: []

Now, the error message states that the OOB Quote object that I am using cannot be linked to a Task using the WhatId. Now, I would have gladly stopped there, but the problem is, there is a lot of functionality that contradicts this error.

Here are some red flags that make me believe there should be some way to set the WhatId with a Quote Id.

Red Flags

Red Flag #1: Email Quote button not only creates an e-mail but a Task, which is shown on the Activity History related list on the Quote detail page.

The standard Email Quote button does create a Task when the e-mail is sent. The only way it would show up on the Quote's detail page, in the Activity History related list no less, is if that Task was linked via the WhatId. Furthermore, you can create a new Task for the Quote via the Open Activities related list. Activity Related List with Task

Red Flag #2: Task detail page shows Related To field going to a Quote

When I clicked on the Task created by the Email Quote button, I looked at the Related To field (which is the WhatId), it links to the Quote I created. Task Detail Part One Now, I thought that maybe it was a mistake, so I chose to edit the Task. But in doing so, it just verified that it was linking to the Quote. Task Detail Part 2

Red Flag #3 (the major one): When I query the Task and inspect the WhatId, it IS the Quote Id!

So to completely verify that the Task's WhatId was being set with a Quote Id, I decided to query the Task using Execute Anonymous. So I entered the following code:

Task taskLinkingToQuote = [SELECT WhatId FROM Task 
    WHERE Id = '00Tj0000009PsWZ' LIMIT 1];
System.Debug(LoggingLevel.Info, taskLinkingToQuote);

But, lo and behold, the WhatId was set the Quote.

Debug Log Linking To Quote

So, somehow, it seems that the Email Quote button can not only create a Task but, it can link the Quote to it via the WhatId.

So now all I can say about the WhatId issue is W.T.F.!? (Sorry, couldn't resist.) This functionality should work in Apex. Hell, there is even code out right now that depends on it, like this one.

Apparently, it worked before. There has even been an issue raised about it here.

So has anyone run into and resolved this issue? Is there anyway around this issue? I haven't tried simply creating a new Task yet, but I wouldn't want to go through the effort and run into the same error.

I would simply like to have the Task appear on the correct detail page - the Quote's. I currently have to suffice with the Opportunity, but I'd like to get the functionality to operate as if it is OOB.

  • You are using OOB Quote or custom Quote__c? In the former case, the error message states that Quote is not one of the allowed use cases
    – cropredy
    Commented Mar 12, 2015 at 1:29
  • I am currently using the OOB Quote. I understand that the error states that this use case isn't allowed. However, this use case is done OOB - contradicting what the error message is saying. I changed my question to highlight the issue. Commented Mar 12, 2015 at 3:11
  • 1
    +1 for the WhatId to WTF association; while I don't know the specific answer to this, I'm sure you can independently insert a Task via DML after you send the email.
    – cropredy
    Commented Mar 12, 2015 at 16:24

2 Answers 2


So I finally got around to fixing the issue.

Just as @crop1645 said, if I simply INSERT the Task via a DML statement, I will be able to create a Task with a Quote's Id as the WhatId.

So before, as a recap, I tried something like this:

Messaging.SingleEmailMessage newEmail = new Messaging.SingleEmailMessage();
newEmail.setToAddresses(new List<String> { emailAddress });
newEmail.setFileAttachments(new List<Messaging.EmailFileAttachment> { newAttachment });
Messaging.sendEmail(new List<Messaging.SingleEmailMessage> { newEmail });

This resulted in throwing the following exception:

System.EmailException: SendEmail failed. First exception on row 0; first error: INVALID_ID_FIELD, Only accounts, assets, campaigns, cases, contracts, opportunities, orders, products, solutions and custom objects are allowed as whatId.: []

Now how I solved it was simple. However, I wanted to make sure I got the Task information exactly like it was done by the Email Quote button. I changed the WhatId for the SingleEmailMessage to the related OpportunityId and after the sendEmail method I followed it with:

Task newQuoteEmailTask = new Task(Subject = 'Email: ' + newEmail.getSubject(), 
     OwnerId = UserInfo.getUserId(), WhatId = quotesId, WhoId = quoteBeingUsed.ContactId,
     Status = 'Completed', ActivityDate = Date.today(), Priority = 'Normal', 
     Description = GenerateTaskComment(newEmail));
INSERT newQuoteEmailTask; 

The Description's method is the following:

private static String GenerateTaskComment(Messaging.SingleEmailMessage newEmail)
    List<String> listOfFileNames = new List<String>();

    for(Messaging.EmailFileAttachment singleAttachment : newEmail.getFileAttachments())

    String endOfDescription = '_____________________________________________________________________'
    + '\nPowered by salesforce.com\nhttp://www.salesforce.com/';

    return 'Additional To: '+ String.join(newEmail.getToAddresses() != null ? newEmail.getToAddresses() : new List<String>(), ',')
        + '\nCC: ' + String.join(newEmail.getCcAddresses() != null ? newEmail.getCcAddresses() : new List<String>(), ',') 
        + '\nBCC: ' + String.join(newEmail.getBccAddresses() != null ? newEmail.getBccAddresses() : new List<String>(), ',') 
        + '\nAttachment'+ (listOfFileNames.size() > 1 ? 's' : '') + ': ' + String.join(listOfFileNames, ',')
        + '\n\nSubject: ' + newEmail.getSubject()
        + '\nBody:\n' + newEmail.getPlainTextBody()
        + '\n\n' + endOfDescription;

Seems like Quote can be associated as WhatId now. I just tested this. See this idea: https://success.salesforce.com/ideaView?id=08730000000l4C0AAI

You must log in to answer this question.

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