You need to sign in to do that
Don't have an account?

Email Enhancements help with setInline and setContentType
We're trying to send out ICS attachments for calendar requests, but we can't seem to get this new feature to work correctly.
Are there any examples in apex to use these changes?
Are there any special configuration changes necessary?
We're using custom objects throughout, so you'll not be able to use the code, but it is self explainitory.
Here is a test we are trying to execute:
public static testMethod void testSendEmail() { testSendEmailHelper('text/x-vCalendar'); testSendEmailHelper('application/x-vCalendar'); testSendEmailHelper('text/calendar'); testSendEmailHelper('application/calendar'); } private static void testSendEmailHelper(String mime){ //AppointmentController uut = new AppointmentController(testUtilities.); //testUtilities. i360_Appointment__c item = testUtilities.GetAppointment(0); // If both Reps are null, we don't send. if (item.Sales_Rep_1__c == null && item.Sales_Rep_2__c == null) return; i360_Prospect__c prospect; String rep1Email; // The email addresses for the reps. String rep2Email; if (item.Prospect__c != null) { prospect = AppointmentUtils.getProspectById(item.Prospect__c); } // Get the email addresses if not null List<String> toAddresses = new List<String>(); if (item.Sales_Rep_1__c != null) { toAddresses.add(AppointmentUtils.getStaffEmailById(item.Sales_Rep_1__c)); } if (item.Sales_Rep_2__c != null) { toAddresses.add(AppointmentUtils.getStaffEmailById(item.Sales_Rep_2__c)); } toAddresses.add('xxxxxxxx@xxxxxxxx.com'); // Set the subject. String subjectLine = ' Appointment Set for ' + item.Start__c.format() + ' ' + item.Start_Time__c; if (prospect != null) { subjectLine = prospect.Name + subjectLine; } /* // These next lines are removed since we'll be creating an Appointment Invite object and trying to send via the server ASAP. */ Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage(); email.setSubject(subjectLine); email.setToAddresses(toAddresses); email.setHtmlBody(AppointmentUtils.getNotificationBody(item.id)); email.setPlainTextBody(AppointmentUtils.getNotificationBodyText(item.id)); // Create an email attachment Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment(); efa.setFileName('Appointment.pdf'); // set name of PDF efa.setBody(AppointmentUtils.getNotificationPDF(item.id)); //attach the PDF Messaging.EmailFileAttachment vcal = new Messaging.EmailFileAttachment(); vcal.setFileName('Appointment.ics'); vcal.setBody(AppointmentUtils.getNotificationVCal(item.id)); vcal.setContentType(mime); vcal.setInLine(true); // email.setPlainTextBody(AppointmentUtils.getNotificationVCalAsString(item.id)); email.setFileAttachments(new Messaging.EmailFileAttachment[] {efa, vcal}); //email.setFileAttachments(new Messaging.EmailFileAttachment[] {vcal}); // send it, ignoring any errors (bad!) Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email}); // Encode the doc and save. Note attach = new Note(); attach.Body = 'Email sent: ' + Date.today(); attach.Title = 'Email sent: ' + Date.today(); attach.ParentId = item.id; insert attach; }
Here is the ICS data in a page
<apex:page standardController="i360_Appointment__c" extensions="AppointmentNotificationController" sidebar="false" showheader="false"> BEGIN:VCALENDAR VERSION:2.0 PRODID://Improveit! 360 CRM METHOD:REQUEST BEGIN:VEVENT SEQUENCE:1 SUMMARY:{!prospect.Name} Appointment - Confirmed={!item.Confirmed__c} DESCRIPTION: {!prospect.Name} Appointment to cover {!item.Components_1__c} {!item.Components_2__c} {!item.Components_3__c} at {!item.Start_Time__c}\n{!item.Address__c} \n{!item.City__c}, {!item.State__c} {!item.Zip__c} LOCATION:{!item.Address__c} {!item.City__c}, {!item.State__c} {!item.Zip__c} CLASS:PUBLIC ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;MAILTO:{!rep1Email} ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP=TRUE:MAILTO:{!rep2Email} UID:{!item.Id} DTSTART:{!zuluStart} DTEND:{!zuluEnd} DTSTAMP:{!zuluCreated} ORGANIZER:MAILTO:{!userEmail} END:VEVENT END:VCALENDAR </apex:page>
p.s.
It does send the email, but doesn't arrive in the expected format. In most cases, such as Outlook, you still need to double click to open, then you can accept the meeting invitation. Doesn't work in Blackberry or gmail.
Yes. For me it is only working that way if I set the content type of the attachment to 'text/calendar'. I really want to send a meeting request that simply shows up in Outlook as meeting request and lets the invitee to accept/decline. Hope some one from Salesforce is reading this.
Hi,
I am getting the following error with the below code. Please advise..
Error: Compile Error: Method does not exist or incorrect signature: [Messaging.EmailFileAttachment].setContentType(String) at line 16 column 9
Code:
public class VF_Test
{
List<String> toAddresses = new List<String>();
public VF_Test()
{
toAddresses.add('sforce2009@gmail.com');
Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
email.setSubject('Test');
email.setToAddresses(toAddresses);
email.setHtmlBody('Test');
email.setPlainTextBody('Test');
Messaging.EmailFileAttachment vcal = new Messaging.EmailFileAttachment();
vcal.setFileName('Appointment.ics');
Blob fileBody;
vcal.setBody(fileBody);
vcal.setContentType('text/Calendar');
vcal.setInLine(true);
email.setFileAttachments(new Messaging.EmailFileAttachment[] {vcal});
Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});
}
}
We are also waiting for help from SalesForce to show us how to do this.
We've attempted executing this in a lookp, sending in different contentTypes and setInLine options. Nothing has worked for us yet.
SUCCESS!!!! We finally have the code and it works. I've attached it below:
Controller:
public class MeetingInviteController { public String sendTo { get; set; } public MeetingInviteController(ApexPages.StandardController controller) { } public PageReference sendInvite() { Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); String[] toAddresses = new String[] {sendTo}; mail.setToAddresses(toAddresses); mail.setSubject('Meeting Invitation'); mail.setPlainTextBody(''); Blob invite = Blob.valueOf('BEGIN:VCALENDAR\nPRODID:-//Microsoft Corporation//Outlook 12.0 MIMEDIR//EN\nVERSION:2.0\nMETHOD:PUBLISH\nX-MS-OLK-FORCEINSPECTOROPEN:TRUE\nBEGIN:VEVENT\nCLASS:PUBLIC\nCREATED:20091026T203709Z\nDTEND:20091028T010000Z\nDTSTAMP:20091026T203709Z\nDTSTART:20091028T000000Z\nLAST-MODIFIED:20091026T203709Z\nLOCATION:Online\nPRIORITY:5\nSEQUENCE:0\nSUMMARY;LANGUAGE=en-us:Meeting\nTRANSP:OPAQUE\nUID:4036587160834EA4AE7848CBD028D1D200000000000000000000000000000000\nX-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//E\n N"><HTML><HEAD><META NAME="Generator" CONTENT="MS Exchange Server ve\n rsion 08.00.0681.000"><TITLE></TITLE></HEAD><BODY><!-- Converted f\n rom text/plain format --></BODY></HTML>\nX-MICROSOFT-CDO-BUSYSTATUS:BUSY\nX-MICROSOFT-CDO-IMPORTANCE:1\nEND:VEVENT\nEND:VCALENDAR'); Messaging.EmailFileAttachment attach = new Messaging.EmailFileAttachment(); attach.filename = 'meeting.ics'; attach.ContentType = 'text/calendar;method=REQUEST'; attach.inline = true; attach.body = invite; mail.setFileAttachments(new Messaging.EmailFileAttachment[] { attach }); Messaging.SendEmailResult[] er = Messaging.sendEmail(new Messaging.Email[] { mail }); return null; }}
Sample Page:
<apex:page standardController="Event" extensions="MeetingInviteController"> <apex:form > <apex:pageBlock > <apex:pageblockSection > Send To: <apex:inputText value="{!sendTo}"/> <apex:inputField value="{!Event.StartDateTime}" /> <apex:commandButton value="send" action="{!sendInvite}"/> </apex:pageblockSection> </apex:pageBlock> </apex:form></apex:page>
Make sure the attendee email in the ICS file and the recipient email match or the user won't receive the Yes/No/Maybe options on the invite. Let me know if you have any questions.
I was running into problems with this too.
You need to make sure your API client (whatever is calling your Apex method or Apex "executeAnonymous" block) is specifying a recent enough API version.
I double-checked and I was specifying "https://www.salesforce.com/services/Soap/u/14.0". Changing that to https://www.salesforce.com/services/Soap/u/17.0" made the code compile & run as expected.
Once you've done that you can use the methods as described in the docs (note the example above actually uses direct instance variable references, which may not be supported long term as it's not in the official doc).
I am little confused. Where in your code did you specify the attendee?