//
you're reading...

Featured

Programmatically Sending Rich Text e-mail with Attachments on the Mac

MailFor a long time now iOS has MFMailComposeViewController for apps to pre-compose an e-mail that the user can send out from his account. However sending e-mail from a Mac OS X app is not as straightforward as it is on iOS. As of this writing, Apple haven’t gotten around to provide an equivalent of that iOS gem.

For years, many apps on the Mac tried to accomplish this by either using mailto URLs that contains a message body or use Scripting Bridge to control OS X’s built-in mail client. However each of these approaches has their limitations – mailto URLs can’t attach files and sandboxing severely limits an app’s capability to script other applications.

Fortunately the OS X provides NSSharingService class that you can use to pre-compose an HTML e-mail with attachments for your users. This may be quite handy if your user needs to create a report of some sort for other people to consume; your app can generate the report as an e-mail with everything ready to go.

Without further ado, here’s how you use NSSharingService to compose a rich text e-mail with attachments:

  1. Prepare these two objects
    • An NSAttributedString instance containing the e-mail body to send.
    • An NSURL instance which points to a local file that you want to attach in the e-mail.
  2. Compose the above two objects into an array. 
  3. Create an NSSharingService object and select the one for sharing via e-mail.
  4. Tell the object to share your array.

Here’s some sample code that may help you

NSAttributedString* textAttributedString = ... // generate the message body here.
NSURL* tempFileURL = ... // write the attachment to that file

NSSharingService* mailShare = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];
NSArray* shareItems = @[textAttributedString,tempFileURL];
[mailShare performWithItems:shareItems];

But I have HTML text to send as e-mail!

No worries. You can simply convert the HTML string into an NSAttributedString with a line of code.

NSString* htmlText = @"<html><body>Hello, <b>World</b>!</body></html>";
NSData* textData = [NSData dataWithBytes:[htmlText UTF8String] length:[htmlText lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
NSAttributedString* textAttributedString = [[NSAttributedString alloc] initWithHTML:textData options:options documentAttributes:nil];

But I dynamically generate the attachment in-memory!

Well, you just have to write out the attachment into a file. Use NSTemporaryDirectory  create a subdirectory under that and write out the file named as what you want to eventually show up in the e-mail message. You shouldn’t worry about removing the file since OS X will clean it up some time after your app quits. Besides, the file needs to be there for Mail to read it and needs to stay there until the user either sends the e-mail message or saves it as draft.

NSUUID* uuid = [NSUUID new];
NSString* tempDir = [NSTemporaryDirectory() stringByAppendingPathComponent:[uuid UUIDString]];
NSFileManager* fm = [NSFileManager new];
[fm createDirectoryAtPath:tempDir withIntermediateDirectories:YES attributes:nil error:nil];

NSString* tempFile = [tempDir stringByAppendingPathComponent:@"report.csv"];
NSURL* tempFileURL = [NSURL fileURLWithPath:tempFile];
NSData* csv = ...; // generate the data here
[csv writeToURL:tempFileURL atomically:NO];
// At this point you can pass tempFileURL to NSSharingService

How do I pre-fill the recipient’s e-mail?

Frankly, I haven’t figured this one out yet. It appears that NSSharingService doesn’t provide a way to specify the destination of the message. I’ve tried adding another NSURL object that contains a mailto scheme in the array of objects to share, but that just appends the URL as a link in the message body. If you figured this out, please do let me know.

That’s all folks. Hope this helps!



Do you enjoy this post? Enter your e-mail address below to receive articles like this one in your mailbox.
  • Götz Fabian

    Great article, thanks! :)
    Looking at the headers of NSSharingService for 10.9, it seems that Apple has added a property recipients of type NSArray. This should allow pre-filling the recipient’s e-mail addresses.

    • Sandeep Tds

      Hi Götz Fabian,

      I am assuming that you could implement this.

      Did your implementation work across clients ? Say for MS Outlook or Mozilla Thunderbird etc.

  • Sandeep Tds

    Hi Samsito,

    I used this article and was able to attach a file only with the Mac Mail App.

    The same code doesn’t attach my file with outlook or thunderbird ?

    Any idea or help ?

Free Updates!

Learn how to grow your indie business while keeping your day job.

Categories

Archives

Keep updated!

Don't miss out on new articles!