* * IMPORTANT - DO NOT USE THE SIMULATOR FOR THIS. * * *
Even in 2016, simulators very simply do not support sending mail from applications.
Indeed, simulators simply do not have email clients.
But! Check out the message below!
Henry gave the full answer. You should
- select and run MFMailComposeViewController at an earlier stage and
- hold it in one static variable and then
- whenever necessary, get a static instance of MFMailComposeViewController and use it.
And you will almost certainly have to cycle through the global MFMailComposeViewController after each use. You cannot reuse the same one.
You have a global routine that frees and then reinitializes a singleton MFMailComposeViewController . Call this global procedure every time you are done with the mail composer.
Do it in any singleton. Do not forget that your application delegate is, of course, singleton, so do it there ...
@property (nonatomic, strong) MFMailComposeViewController *globalMailComposer; -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ........
and...
-(void)cycleTheGlobalMailComposer { // cycling GlobalMailComposer due to idiotic iOS issue self.globalMailComposer = nil; self.globalMailComposer = [[MFMailComposeViewController alloc] init]; }
Then, to use mail, something like this ...
-(void)helpEmail { // APP.globalMailComposer IS READY TO USE from app launch. // recycle it AFTER OUR USE. if ( [MFMailComposeViewController canSendMail] ) { [APP.globalMailComposer setToRecipients: [NSArray arrayWithObjects: emailAddressNSString, nil] ]; [APP.globalMailComposer setSubject:subject]; [APP.globalMailComposer setMessageBody:msg isHTML:NO]; APP.globalMailComposer.mailComposeDelegate = self; [self presentViewController:APP.globalMailComposer animated:YES completion:nil]; } else { [UIAlertView ok:@"Unable to mail. No email on this device?"]; [APP cycleTheGlobalMailComposer]; } } -(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error { [controller dismissViewControllerAnimated:YES completion:^ { [APP cycleTheGlobalMailComposer]; } ]; }
{nb, fixed typo on Michael Salamon below.}
You have the following macro in your prefix file
#define APP ((AppDelegate *)[[UIApplication sharedApplication] delegate])
There is also a βminorβ problem that may cost you days: https://stackoverflow.com/a/416829/
For 2016 FTR only, here is the basic quick code to send IN APP email,
class YourClass:UIViewController, MFMailComposeViewControllerDelegate { func clickedMetrieArrow() { print("click arrow! v1") let e = MFMailComposeViewController() e.mailComposeDelegate = self e.setToRecipients( ["help@smhk.com"] ) e.setSubject("Blah subject") e.setMessageBody("Blah text", isHTML: false) presentViewController(e, animated: true, completion: nil) } func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) { dismissViewControllerAnimated(true, completion: nil) }
However! Attention!
These crappy days send an "in-app" email.
Itβs much better today just to disable the mail client.
Add to plist ...
<key>LSApplicationQueriesSchemes</key> <array> <string>instagram</string> </array>
and then enter the code as
func pointlessMarketingEmailForClient() { let subject = "Some subject" let body = "Plenty of <i>email</i> body." let coded = "mailto:blah@blah.com?subject=\(subject)&body=\(body)".stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet()) if let emailURL:NSURL = NSURL(string: coded!) { if UIApplication.sharedApplication().canOpenURL(emailURL) { UIApplication.sharedApplication().openURL(emailURL) } else { print("fail A") } } else { print("fail B") } }
These days, it's much better than trying to send an email from within the app.
Remember that iOS simulators simply do not have email clients (and you cannot send emails using the composer in the application). You must test the device.