How to Send Email Using Mfmailcomposeviewcontroller in Simulator

Unable to send email using MFMailComposeViewController in simulator

You CANNOT send mails through Simulator.

Instead you can install the application in device and try from there.

Simulator just displays the composer but wont allow you to send mails. Sent Successfully is just the acknowledgment that your code is fine and there is no issue that terminates it while sending.

SwiftUI: Send email using MFMailComposeViewController

Building up on the code snippet shared in my original question:

Based on the answer from @Arjun this is my current workaround to account for the edge case that someone might have deleted the Apple Mail app and is using another email app:

Button(action: {
if MailComposeViewController.shared.thisIsTest() {
MailComposeViewController.shared.sendEmail()
} else {
openURL(URL(string: "mailto:someone@example.com?subject=This%20is%20the%20subject")!)
}
}, label: {
Text("Send")
})

It opens the in-app sheet as long as the user has set up apple mail and otherwise switches to any other email app using a mailto: link.

MFMailComposeViewController is this supposed to actually sendmail from the simulator?

No, the simulator does not actually support email accounts or allow you to really send mail.

[MFMailComposeViewController canSendMail] returns YES to allow you to fully test your mail generation and compose code paths. As far as your app should be concerned, it behaves exactly like a real device (since the user can choose to cancel out anyways on the real thing), although you cannot inspect the actual contents of the resulting email without testing on a real device.

How to send an email through iOS simulator?

You have to rely on the iOS that the MFMailComposeResult that is handed back in mailComposeController:didFinishWithResult:error: is correct. The simulator fakes that result; no actual mail is sent although it says MFMailComposeResultSent.

The tutorial mentioned misses an important point: The first thing you should do before using MFMailComposeViewController is to check [MFMailComposeViewController canSendMail]. That will return NO, if the user hasn't configured mail on their device. If you must support an iOS version prior to 3.0 the correct way is to check if the class MFMailComposeViewController exists:

Class mailClass = (NSClassFromString(@"MFMailComposeViewController"));
if (mailClass != nil)
{
if ([mailClass canSendMail])
{
[self displayComposerSheet];
}
else
{
[self launchMailAppOnDevice];
}
}
else
{
[self launchMailAppOnDevice];
}

The canSendMail-issue can only be tested on a real device though. It will crash if you don't check canSendMail and the user has no mail account configured.

I have REAL misunderstanding with MFMailComposeViewController in Swift (iOS8) in Simulator

* * IMPORTANT - DO NOT USE THE SIMULATOR FOR THIS. * *

Even in 2016, the simulators very simply do not support sending mail from apps.

Indeed, the simulators simply do not have mail clients.

But! Do see the message at the bottom!


Henri has given the total answer. You MUST

-- allocate and initiate MFMailComposeViewController in an earlier stage, and

-- hold it in one static variable, and then,

-- whenever it's needed, get the static MFMailComposeViewController instance and use that.

AND you will almost certainly have to cycle the global MFMailComposeViewController after each use. It is not reliable to re-use the same one.

Have a global routine which releases and then re-initializes the singleton MFMailComposeViewController. Call to that global routine, each time, after you are finished with the mail composer.

Do it in any singleton. Don't forget that your app delegate is, of course, a singleton, so do it there...

@property (nonatomic, strong) MFMailComposeViewController *globalMailComposer;

-(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
........
// part 3, our own setup
[self cycleTheGlobalMailComposer];
// needed due to the worst programming in the history of Apple
.........
}

and...

-(void)cycleTheGlobalMailComposer
{
// cycling GlobalMailComposer due to idiotic iOS issue
self.globalMailComposer = nil;
self.globalMailComposer = [[MFMailComposeViewController alloc] init];
}

Then to use the 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 per Michael Salamone below.}

Have the following macro in your Prefix file for convenience

#define APP ((AppDelegate *)[[UIApplication sharedApplication] delegate])

Also here's a "minor" problem which can cost you days: https://stackoverflow.com/a/17120065/294884


Just for 2016 FTR here's the basic swift code to send an email IN APP,

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! Note!

These days it is crappy to send an email "in app".

It's much better today to simply cut away to the email client.

Add to plist ...

<key>LSApplicationQueriesSchemes</key>
<array>
<string>instagram</string>
</array>

and then code like

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, that is much better than trying to email from "inside" the app.

Remember again the iOS simulators simply do not have email clients (nor can you send email using the composer within an app). You must test on a device.

Sent email from IOS Simulator but not receiving in mailbox

You can't send mail from Simulator. You need to setup Mail Account from Settings to be able to do that, which is not available in Simulators Settings, its available only in Devices.

Trying to send an email through an iphone app and getting an error using MFMailComposeViewController in iOS 8

This is a known error in the simulator. It does not appear when you run on a device. So, try it on a device and if it runs normally, then you should be ok.



Related Topics



Leave a reply



Submit