Dani's answer is great, however the code seems to be too long for someone looking for a simple way to send an attachment through email programatically.
The Gist
I pruned his answer to take out only the important bits, as well as refactored it like so:
MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
mailComposer.mailComposeDelegate = self;
mailComposer.subject = @"Sample subject";
mailComposer.toRecipients = @[@"arthur@example.com", @"jeanne@example.com", ...];
mailComposer.ccRecipients = @[@"nero@example.com", @"mashu@example.com", ...];
[mailComposer setMessageBody:@"Sample body" isHTML:NO];
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
[mailComposer addAttachmentData:fileData
                       mimeType:mimeType
                       fileName:fileName];
[self presentViewController:mailComposer animated:YES completion:nil];
That's basically the gist of it, this is enough as it is. If, for example, you put this code on a button's action, it will present an email composing screen with the respective fields pre-filled up, as well as having the file you want attached to the email.
Further Reading
Framework
The MFMailComposeViewController is under the MessageUI Framework, so to use it, import (if you have not done yet) the Framework like so:
#import <MessageUI/MessageUI.h>
Mail Capability Checking
Now when you run the source code, and you have not yet setup a mail account on your device, (not sure what the behavior is on simulator), this code will crash your app. It seems that if the mail account is not yet setup, doing [[MFMailComposeViewController alloc] init] will still result in the mailComposer being nil, causing the crash. As the answer in the linked question states:
You should check is MFMailComposeViewController are able to send your mail just before sending
You can do this by using the canSendMail method like so:
if (![MFMailComposeViewController canSendMail]) {
    [self openCannotSendMailDialog];
    return;
}
You can put this right before doing [[MFMailComposeViewController alloc] init] so that you can notify the user immediately.
Handling cannotSendMail
If canSendMail returns false, according to Apple Dev Docs, that means that the device is not configured for sending mail. This could mean that maybe the user has not yet setup their Mail account. To help the user with that, you can offer to open the Mail app and setup their account. You can do this like so:
NSURL *mailUrl = [NSURL URLWithString:@"message://"];
if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) {
    [[UIApplication sharedApplication] openURL:mailUrl];
}
You can then implement openCannotSendMailDialog like so:
- (void)openCannotSendMailDialog
{
    UIAlertController *alert =
        [UIAlertController alertControllerWithTitle:@"Error"
                                            message:@"Cannot send mail."
                                preferredStyle:UIAlertControllerStyleAlert];
        
    NSURL *mailUrl = [NSURL URLWithString:@"message://"];
    if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"Open Mail"
                                  style:UIAlertActionStyleDefault
                                handler:^(UIAlertAction * _Nonnull action) {
            [[UIApplication sharedApplication] openURL:mailUrl];
        }]];
        
        [alert addAction:
         [UIAlertAction actionWithTitle:@"Cancel"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {
            
        }]];
        
    } else {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"OK"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {
            
        }]];
        
    }
        
    [self presentViewController:alert animated:YES completion:nil];
}
Mime Types
If like me, you forgot/are unsure which mimeType to use, here is a resource you can use. Most probably, text/plain is enough, if the file you are attaching is just a plain text, or image/jpeg / image/png for images.
Delegate
As you probably noticed, Xcode throws us a warning on the following line:
mailComposer.mailComposeDelegate = self; 
This is because we have not yet set ourself to conform to the appropriate protocol and implement its delegate method. If you want to receive events whether the mail was cancelled, saved, sent or even failed sending, you need to set your class to conform to the protocol MFMailComposeViewControllerDelegate, and handle the following events:
- MFMailComposeResultSent
 
- MFMailComposeResultSaved
 
- MFMailComposeResultCancelled
 
- MFMailComposeResultFailed
 
According to Apple Dev Docs (emphasis mine):
The mail compose view controller is not dismissed automatically. When the user taps the buttons to send the email or cancel the interface, the mail compose view controller calls the mailComposeController:didFinishWithResult:error: method of its delegate. Your implementation of that method must dismiss the view controller explicitly.
With this in mind, we can then implement the delegate method like so:
- (void)mailComposeController:(MFMailComposeViewController *)controller
          didFinishWithResult:(MFMailComposeResult)result
                        error:(NSError *)error
{
    switch (result) {
        case MFMailComposeResultSent:
            // Mail was sent
            break;
        case MFMailComposeResultSaved:
            // Mail was saved as draft
            break;
        case MFMailComposeResultCancelled:
            // Mail composition was cancelled
            break;
        case MFMailComposeResultFailed:
            // 
            break;
        default:
            // 
            break;
    }
    
    // Dismiss the mail compose view controller.
    [controller dismissViewControllerAnimated:YES completion:nil];
}
Conclusion
The final code may look like so:
- (void)openMailComposerWithSubject:(NSString *)subject
                   toRecipientArray:(NSArray *)toRecipientArray
                   ccRecipientArray:(NSArray *)ccRecipientArray
                        messageBody:(NSString *)messageBody
                  isMessageBodyHTML:(BOOL)isHTML
                attachingFileOnPath:(NSString)filePath
                           mimeType:(NSString *)mimeType
{
    if (![MFMailComposeViewController canSendMail]) {
        [self openCannotSendMailDialog];
        return;
    }
    MFMailComposeViewController *mailComposer = 
        [[MFMailComposeViewController alloc] init];
    mailComposer.mailComposeDelegate = self;
    
    mailComposer.subject = subject;
    
    mailComposer.toRecipients = toRecipientArray;
    mailComposer.ccRecipients = ccRecipientArray;
    
    [mailComposer setMessageBody:messageBody isHTML:isHTML];
    
    NSData *fileData = [NSData dataWithContentsOfFile:filePath];
    NSString *fileName = filePath.lastPathComponent;
    [mailComposer addAttachmentData:fileData
                           mimeType:mimeType
                           fileName:fileName];
    
    [self presentViewController:mailComposer animated:YES completion:nil];
}
- (void)openCannotSendMailDialog
{
    UIAlertController *alert =
        [UIAlertController alertControllerWithTitle:@"Error"
                                            message:@"Cannot send mail."
                                preferredStyle:UIAlertControllerStyleAlert];
    
    NSURL *mailUrl = [NSURL URLWithString:@"message://"];
    if ([[UIApplication sharedApplication] canOpenURL:mailUrl]) {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"Open Mail"
                                  style:UIAlertActionStyleDefault
                                handler:^(UIAlertAction * _Nonnull action) {
            [[UIApplication sharedApplication] openURL:mailUrl];
        }]];
        
        [alert addAction:
         [UIAlertAction actionWithTitle:@"Cancel"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {
            
        }]];
        
    } else {
        [alert addAction:
         [UIAlertAction actionWithTitle:@"OK"
                                  style:UIAlertActionStyleCancel
                                handler:^(UIAlertAction * _Nonnull action) {
            
        }]];
        
    }
        
    [self presentViewController:alert animated:YES completion:nil];
}
- (void)mailComposeController:(MFMailComposeViewController *)controller
          didFinishWithResult:(MFMailComposeResult)result
                        error:(NSError *)error
{
    NSString *message;
    switch (result) {
        case MFMailComposeResultSent:
            message = @"Mail was sent.";
            break;
        case MFMailComposeResultSaved:
            message = @"Mail was saved as draft.";
            break;
        case MFMailComposeResultCancelled:
            message = @"Mail composition was cancelled.";
            break;
        case MFMailComposeResultFailed:
            message = @"Mail sending failed.";
            break;
        default:
            // 
            break;
    }
    // Dismiss the mail compose view controller.
    [controller dismissViewControllerAnimated:YES completion:^{
        if (message) {
            UIAlertController *alert =
                [UIAlertController alertControllerWithTitle:@"Confirmation"
                                                    message:message
                                        preferredStyle:UIAlertControllerStyleAlert];
    
            [alert addAction:
             [UIAlertAction actionWithTitle:@"OK"
                                      style:UIAlertActionStyleCancel
                                    handler:^(UIAlertAction * _Nonnull action) {
                
            }]];
            [self presentViewController:alert animated:YES completion:nil];
        }
    }];
}
With the button action looking like:
- (IBAction)mailButtonTapped:(id)sender
{
    NSString *reportFilePath = ...
    [self openMailComposerWithSubject:@"Report Files"
                     toRecipientArray:mainReportRecipientArray
                     ccRecipientArray:subReportRecipientArray
                          messageBody:@"I have attached report files in this email"
                    isMessageBodyHTML:NO
                  attachingFileOnPath:reportFilePath
                             mimeType:@"text/plain"];       
}
I kind of went overboard here, but you can, with a grain of salt, take and use the code I posted here. Of course there is a need to adapt it to your requirements, but that is up to you. (I also modified this answer from my working source code, so there might be errors somewhere, please do comment if you find one :))