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.setTargetObjectId(quoteBeingUsed.ContactId);
newEmail.setWhatId(quotesId);
newEmail.setTemplateId(TemplateId);
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())
listOfFileNames.add(singleAttachment.getFileName());
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;
}
From the Apex Code Developer's Guide:
setSaveAsActivity(saveAsActivity)
The default value is true, meaning the email is saved as an activity. This argument only applies if the recipient list is based on targetObjectId or targetObjectIds. If HTML email tracking is enabled for the organization, you will be able to track open rates.
The above method relies on you using setTargetObjectIds
, to set the WhoID(s) for your email message. If you set the targetobjectIds as anything other than contacts or leads, then you'll have a problem because it creates a Task that's assigned on that Contact or Lead that can also be related to a WhatId.
setWhatId(whatId)
If you specify a contact for the targetObjectId field, you can specify an optional whatId as well. This helps to further ensure that merge fields in the template contain the correct data.
Usage:
The value must be one of the following types:
- Account
- Asset
- Campaign
- Case
- Contract
- Opportunity
- Order
- Product
- Solution
- Custom
Best Answer
Using Newly introduced method
setTreatTargetObjectAsRecipient()
in Winter 16, you can send email message to any email address.