3

I have a page where the user selects content (that is 5MB or lower, only 2 attachments allowed per email) to use as an attachment in an email. It all seems to work fine, the email sends and there are attachments in it with the correct title. But the attachments themselves seems to be broken. There is nothing in them, or i get Forbidden Error 403 when i try to download them.

I have tried it will 3 types of content (power_point_x, power_point, pdf) and all fail like this. also when looking at the attachment in google drive, in the details section it says all three have a type of Mime type: application/octet-stream ? I know i am missing something simple here I am sure lol, just looking for some guidance.

Thanks!

  List<Messaging.EmailFileAttachment> attList = new List<Messaging.EmailFileAttachment>();
  Messaging.EmailFileAttachment efa;
  if (!selectedContent.isEmpty()) {
    for (ContentVersion cv : PromoModel_Helper.findSelected(selectedContent)) {
      if (cv != null) {
        efa = new Messaging.EmailFileAttachment();
        efa.setFileName(cv.Title);
        efa.setBody(cv.VersionData);
        attList.add(efa);
      }
    } 
  }

  mail = new Messaging.SingleEmailMessage();
  mail.setToAddresses(sendToIds);
  mail.setReplyTo(replyToEmail);
  mail.setSenderDisplayName(senderDisplayName);
  mail.setBccSender(bcc);
  mail.setUseSignature(signature);
  mail.setSubject(subject);
  mail.setHtmlBody(body);

  if (!attList.isEmpty()) {
    mail.setFileAttachments(attList);
  }

  try {
    List<Messaging.SendEmailResult> results = Messaging.sendEmail(
      new List<Messaging.Email> { mail }
    );
  } catch (Exception e) {
    ApexPages.addMessage(new ApexPages.Message(
      ApexPages.Severity.ERROR, 
      'An Error occured while trying to email, ' + e.getMessage()
    ));
    return null;
  }

Update: So i tried adding efa.setContentType(cv.FileType); which created an error saying the Messaging.SingleEmailMessage was Not Serializable, so I tried making it transient. That created an error around the file type:

An Error occured while trying to email, SendEmail failed. 
First exception on row 0; first error: INVALID_CONTENT_TYPE, An invalid value was specified for contentType.: []

The output of the cv.FileType is typically (PDF, POWER_POINT_X, POWER_POINT, WORD, EXCEL_X) and this seems to not work (given the error above, and yes i checked that it was getting the value i expected) So I tried converting it to file extensions

efa.setContentType(
  (cv.FileType == 'POWER_POINT_X' ? 
    '.pptx' : cv.FileType == 'POWER_POINT' ?
      '.ppt' : cv.FileType == 'PDF' ?
        '.pdf' : cv.FileType == 'EXCEL' ? 
          '.xls' : '.doc')
);

and still no joy :-(

10
  • try efa.setContentType(cv.FileType); ? Commented Jan 28, 2014 at 18:11
  • I think you may also have to decode it, as VersionData is converted to Base64. EncodingUtil.Base64Decode Commented Jan 28, 2014 at 18:20
  • when i add the efa.setContentType(cv.FileType); the page errors with "Not Serializable: Messaging.SingleEmailMessage" Also the EncodingUtil.Base64Decode takes a string and outputs a blob, and since force.com reads VersionData as a blob it errors with 'Method does not exist or incorrect signature: EncodingUtil.Base64Decode(Blob)' So i tried converting it to a string and then when i sent the email i got 'Unrecognized base64 character: [ Error is in expression '{!sendMail}' in component <apex:commandButton>' Commented Jan 28, 2014 at 19:10
  • Yeah, I wasn't sure about the decoding part, and it may not be necessary if it is returning a blob (weird that is typed as base64 in the schema) Commented Jan 28, 2014 at 20:05
  • right? lol i thought the same thing! Commented Jan 28, 2014 at 20:06

2 Answers 2

2

As Daniel stated, you need to set the MIME Content-Type of the email attachment using the setContentType method. Unfortunately, ContentVersion.filetype is only returning the extension from (pdf, ppt, etc.), and the Content-Type is expecting the top-level media type as well. A registry of the top-level MIME Content-Types and their associated sub-types can be found at http://www.iana.org/assignments/media-types/media-types.xhtml, and one solution would be to get the extension, and then manually put the correct MIME Type (i.e. if ContentVersion.Filetype returns 'pdf', setContentType would need to recieve 'application/pdf')

Hopefully you don't have a lot of file types to deal with.

Instead of having a bunch of conditionals, it would also be possible to work this out through custom settings. Apache keeps a mime.types file that has a list of extensions with their associated MIME type here: http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types. You could make a custom setting for the extensions and their related MIME Type, and then query the custom setting to retrieve the extensions MIME Type.

2
  • well its not returning a .extension its returning things like POWER_POINT or EXCEL_X etc :-P but yes now i have to figure out all the different types and then what that translates to :-P Commented Jan 28, 2014 at 21:21
  • Added a thought on that to the answer. It would take some building out, but would work out better in the long run. Either way it is going to take some work to figure out what Filetype is returning, and then getting the proper MIME Type associated :( Commented Jan 28, 2014 at 21:24
5

You will need to set the Mime Content-Type of the attachment to match that of the ContentVersion. This will tell your browser/mail client how to open the attachment.

The Mime Type for the ContentVersion is in FileType.

You can set the Mime Type on the EmailFileAttachment using setContentType().

efa = new Messaging.EmailFileAttachment();
efa.setFileName(cv.Title);

// Set the Attachment Mime Type to match that of the ContentVersion
efa.setContentType(cv.FileType);

efa.setBody(cv.VersionData);
attList.add(efa);

Also, it may not be strictly required, but you could also set the Content-Disposition to attachment for good measure.

efa.setInline(false);

So it appears the FileType doesn't directly map the the Mime Content-Type.

You will need to create a lookup structure to go from the stored value to the correct Mime type. Note that this isn't the same thing as a file extension.

Map<string, string> mimeTypeMap = new Map<string, string>();
mimeTypeMap.put('POWER_POINT_X', 'application/vnd.openxmlformats-officedocument.presentationml.presentation');
mimeTypeMap.put('POWER_POINT', 'application/vnd.ms-powerpoint');
mimeTypeMap.put('EXCEL', 'application/vnd.ms-excel');
// And so on...

// Should probably check here the the FileType is registered in the map.
efa.setContentType(mimeTypeMap.get(cv.FileType));
10
  • thanks, but I tried that I got an error when the email was sent: Not Serializable: Messaging.SingleEmailMessage Commented Jan 28, 2014 at 19:13
  • That error would suggest your code is running in something like a batch. Maybe mark the Messaging.EmailFileAttachment efa as transient. Commented Jan 28, 2014 at 19:19
  • weird that it thinks its in a batch.. when it isnt at all.. i'll try it. Commented Jan 28, 2014 at 19:21
  • An Error occured while trying to email, SendEmail failed. First exception on row 0; first error: INVALID_CONTENT_TYPE, An invalid value was specified for contentType.: [] Commented Jan 28, 2014 at 19:28
  • and when i output the content type its how it is from the content (POWER_POINT, PDF, POWER_POINT_X). I tried all three individually to make sure it wasnt an issue with one type in particular. Commented Jan 28, 2014 at 19:30

You must log in to answer this question.

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