This content has been archived.


Older content from our site that still has value for lots of developers!

Email Tutorial for iOS: How To Import and Export App Data Via Email in your iOS App

An email tutorial showing you how you can import and export your app’s data via email in your iOS app.


  • Other, Other, Other
Load Attachments In Your App!

Load Attachments In Your App!

A lot of developers want to be able to share their app data via email. It’s a convenient way for users to send data to each other or between devices – and it may even net you some new customers!

Luckily, this is pretty easy to do on the iPhone – you just have to set a few keys in your Info.plist and handle a few callbacks so the OS can open your app with the URL to import.

So we’ll cover how to do exactly that in this email tutorial!

We’re going to start with the Scary Bugs project we’ve been building starting from the simple app tutorial on up to the file sharing tutorial.

So if you don’t have a copy of the project where we left off already, grab a copy!

Setting Up Your Info.plist

We’ve already laid most of the groundwork we need in order to support sharing our app data via email – we’ve written code to save a copy of our app data as a single file.

So the next thing we need to do is set up our Info.plist to let the OS know that we can handle “Scary Bug Documents”. The way you do this on iOS is by registering your app as able to handle certain UTIs, and exporting any UTIs that are not already known by the system.

In summary, UTIs are just unique identifiers that represent your document, such as “com.raywenderlich.scarybugs.sbz”. There are built-in ones for common document types such as “public.jpeg” or “public.html” as well.

So we’re register our app as being able to handle a UTI we make up for our app, and then we’re going to tell the OS a bit about our UTI, such as what file name extension it uses and what mime-type it’s encoded as in email.

So let’s see it in action! Open up ScaryBugs-Info.plist, and add the following entries:

Info.plist Setup for App Documents

You can read up on what each of these value’s mean in Apple’s UTI guide, but here are the important things to note:

  • The CFBundleDocumentTypes entry says what UTIs our app supports – in this case, the com.raywenderlich.scarybugs.sbz UTI, as an Owner/Editor.
  • The UTExportedTypeDeclaration entry gives some information about com.raywenderlich.scarybugs.sbz, since it isn’t a public UTI. Here we say that any file ending in .sbz or has a mime type of application/scarybugs is that kind of file.

Believe it or not, by setting these keys that’s all it takes for the OS to start sending our app files that end with .sbz. You can test it out by emailing yourself a copy of this sample bug if you want:

Emailed Bug Screenshot

You can hold and tap on the attachment and it will prompt you if you want to open it in Scary Bugs. If you do, it will open up Scary Bugs, but of course it won’t load because we haven’t added the code for that yet! So let’s do that next.

Importing App Data

When Mail or some other app wants to send your app a file, it does so via one of two methods: via application:didFinishLaunchingWithOptions, passing the URL in the UIApplicationLaunchOptionsURLKey, or via application:handleOpenURL.

To understand what happens when, Oliver Drobnick has put together a very handy article with diagrams on what gets called when.

So let’s implement that real quick – it will be easy since we already have much of the supporting code in place. Make the following mods to ScaryBugDoc.h:

// After @interface
- (BOOL)importFromURL:(NSURL *)importURL;

The following to ScaryBugDoc.m:

// Add new function
- (BOOL)importFromURL:(NSURL *)importURL {
    NSData *zippedData = [NSData dataWithContentsOfURL:importURL];
    return [self importData:zippedData];    

The following in RootViewController.h:

// After @interface
- (void)handleOpenURL:(NSURL *)url;

And the following in RootViewController.m:

// New method
- (void)handleOpenURL:(NSURL *)url {
    [self.navigationController popToRootViewControllerAnimated:YES];
    ScaryBugDoc *newDoc = [[[ScaryBugDoc alloc] init] autorelease];
    if ([newDoc importFromURL:url]) {
        [self addNewDoc:newDoc];       

Finally add the following to ScaryBugsAppDelegate.m:

// Add at end of application:didFinishLaunchingWithOptions
NSURL *url = (NSURL *)[launchOptions valueForKey:UIApplicationLaunchOptionsURLKey];
if (url != nil && [url isFileURL]) {
        [rootController handleOpenURL:url];                

// Add new method
-(BOOL) application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    RootViewController *rootController = (RootViewController *) [navigationController.viewControllers objectAtIndex:0];
    if (url != nil && [url isFileURL]) {
        [rootController handleOpenURL:url];                
    return YES;

This is mostly self-explanatory, but a few notes.

First, in ScaryBugDoc we add a method to import a document from a URL. The URL that is passed into us from the system is actually a copy of the document that is placed somewhere in our app’s directory. So we read it out here as an NSData and pass it to our importData method that we wrote earlier.

In RootViewController, we pop to the root view controller (in case we were on a details view somewhere), create a new doc, and import from the given URL.

In ScaryBugsAppDelegate, in both places where we can receive a URL we look for it, and if it’s a file URL (rather than a query string, might have a tutorial on that later), we notify the root view controller so it can do the import.

So go ahead and compile and run your app, and if all works well you should be able to open up the email attachment and see the bug imported into your app!

Imported Bug

Exporting App Data

That was the hard part – exporting data will be smooth sailing from here.

Make the following changes to EditBugViewController.h:

// Add to the top of the file
#import <MessageUI/MessageUI.h>

// Modify EditBugViewController to have two new protocols: UIActionSheetDelegate and MFMailComposeViewControllerDelegate
@interface EditBugViewController : UIViewController <UITextFieldDelegate, RateViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIAlertViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate> {

Then make the following changes to EditBugViewController.m:

// Replace exportTapped with the following:
- (void)exportTapped:(id)sender {
    UIActionSheet *actionSheet = [[[UIActionSheet alloc]
                                   otherButtonTitles:@"Export via File Sharing", @"Export via Email", nil] autorelease];
    [actionSheet showInView:self.view];

// Add new methods
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex == actionSheet.firstOtherButtonIndex + 0) {
        [DSBezelActivityView newActivityViewForView:self.navigationController.navigationBar.superview withLabel:@"Exporting Bug..." width:160];   
        [_queue addOperationWithBlock: ^{
            BOOL exported = [_bugDoc exportToDiskWithForce:FALSE];
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                [DSBezelActivityView removeViewAnimated:YES];
                if (!exported) {
                    UIAlertView *alertView = [[[UIAlertView alloc] 
                                               initWithTitle:@"File Already Exists!" 
                                               message:@"An exported bug with this name already exists.  Overwrite?" 
                                               otherButtonTitles:@"Overwrite", nil] autorelease];
                    [alertView show];
    } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 1) {
        [DSBezelActivityView newActivityViewForView:self.navigationController.navigationBar.superview withLabel:@"Exporting Bug..." width:160];   
        [_queue addOperationWithBlock: ^{
            NSData *bugData = [_bugDoc exportToNSData];
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                [DSBezelActivityView removeViewAnimated:YES];
                if (bugData != nil) {
                    MFMailComposeViewController *picker = [[[MFMailComposeViewController alloc] init] autorelease];
                    [picker setSubject:@"My Scary Bug"];
                    [picker addAttachmentData:bugData mimeType:@"application/scarybugs" fileName:[_bugDoc getExportFileName]];
                    [picker setToRecipients:[NSArray array]];
                    [picker setMessageBody:@"Check out this scary bug!  You'll need a copy of ScaryBugs to view this file, then tap and hold to open." isHTML:NO];
                    [picker setMailComposeDelegate:self];
                    [self presentModalViewController:picker animated:YES];                    

- (void)mailComposeController:(MFMailComposeViewController *)controller
						error:(NSError *)error {
    [self dismissModalViewControllerAnimated:YES];

Here we modify the export button to prompt the user whether they want to export via File Sharing as before, or via email.

If the user chooses via email, we use a MFMailComposeViewController to create an email message, and we add ad attachment with our bug data to the message. Pretty simple eh?

One last thing before we can test: right click on Frameworks, click “Add\Existing Framework…” and choose “MessageUI.framework” from the list.

Then compile and run your app, and you should be able to automatically export a scary bug from your app via email!

Emailing Bug

Let’s Have Some Fun!

If you’ve gotten this far, why not have some fun?

Create a scary bug with the app, then email it to me at the email address in the above screenshot, and I’ll add it to this post! Let’s see what freakish creatures we can come up with! :]

Update: Here’s a not-so-scary bug submitted by Alex Hedley! :]

Where To Go From Here?

Here is a sample project with all of the code we’ve developed so far in this tutorial series.

This is as far as my plans go for this Scary Bugs app, but who knows, maybe we’ll come back to it someday?

In the meantime, let me know if you have any questions or comments – and what bugs you think are the scariest! :]

Add a rating for this content