Click alert button to show MFMailComposeViewController
Your code tries to present the mail view controller (and also the error alert) on a new view controller which you create with instantiateViewController
. Since this new VC itself is not part of your app's VC hierarchy, neither it nor the mail VC will appear on screen.
To make this work, you can either pass a view controller which is part of your app into your sendmail
method:
func sendmail(_ root: UIViewController) {
...
root.present(mailComposeViewController, animated: true, completion: nil)
...
Or you can use a globally accessible VC of your app; in a simple app using the root VC should work:
func sendmail() {
...
let root = UIApplication.shared.keyWindow?.rootViewController
root?.present(mailComposeViewController, animated: true, completion: nil)
...
I'd suggest the first approach because it is more flexible (e.g. it allows you to open your mail screen anywhere, even when your VC hierarchy gets more complex).
Privacy Problems with MFMailComposeViewController and iOS 10 only
So after much analysis I finally figured this problem out last weekend. The key to knowing it actually had nothing to do with MFMailComposeViewController privacy changes in iOS 10 was this log message:
[MC] Result: YES
If you get a "NO" then you have a privacy problem, but a YES indicates that privacy was not an issue. I finally found, in my case here anyway, that the problem was is a timing issue in my code uncovered running in iOS 10.
On the same exact device model being testing, one with iOS 10 and one with iOS 9.3.5 the problem was an error path UIAlertController present request being called when another alert was already presented. On iOS 9.x and earlier it was just "luck" that the expected one won out and got presented first every single time. But on iOS 10 it failed to do so every single time and this then blocked the MFMailComposeViewController in my situation.
The following code was problematic :
[self presentViewController:crashMailAlertController animated:YES completion:nil];
Replacing it with this code resolved the issue:
[self dismissViewControllerAnimated:YES completion:^{
[self presentViewController:crashMailAlertController animated:YES completion:nil];
}];
In my case all I wanted was to insure that this error path UIAlertController was always presented first as it was a rare event (only when a crash had happened), so dismissing any previous alert first was the ticket to getting it up so that the MFMailComposeViewController would follow as it was embedded in the alert button action.
Getting a black screen when clicking the contact button prior to the send button
Please use the code to open mail in swift with an extension like below.
extension SendEmailVC: MFMailComposeViewControllerDelegate {
func contact() {
if !MFMailComposeViewController.canSendMail() {
ROAlert.warningAlertUnderNavigation(ROConstants.More.kNoMailConfigured, onView: self.view)
return ()
}
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
composeVC.setToRecipients([ROConstants.More.kContactEmail])
// Present the view controller modally.
self.present(composeVC, animated: true, completion: nil)
}
//MARK: - MFMailComposeViewControllerDelegate
func mailComposeController(_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult, error: Error?) {
// Check the result or perform other tasks.
// Dismiss the mail compose view controller.
controller.dismiss(animated: true, completion: nil)
}
}
Getting a black screen when clicking the contact button prior to the send button
Please use the code to open mail in swift with an extension like below.
extension SendEmailVC: MFMailComposeViewControllerDelegate {
func contact() {
if !MFMailComposeViewController.canSendMail() {
ROAlert.warningAlertUnderNavigation(ROConstants.More.kNoMailConfigured, onView: self.view)
return ()
}
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
composeVC.setToRecipients([ROConstants.More.kContactEmail])
// Present the view controller modally.
self.present(composeVC, animated: true, completion: nil)
}
//MARK: - MFMailComposeViewControllerDelegate
func mailComposeController(_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult, error: Error?) {
// Check the result or perform other tasks.
// Dismiss the mail compose view controller.
controller.dismiss(animated: true, completion: nil)
}
}
How to add a UIImage in MailComposer Sheet of MFMailComposeViewController
Back again with a new answer. I'm still leaving my previous code up though, because I'm still not convinced that there's not a way to make use of it. I'll keep at it myself. The following code DOES work. Mustafa suggests base64 encoding the images, and says that they only work Apple to Apple, but that's not actually true. Base64 encoding does work with most mail clients now (IE previously didn't support it, but now it is supported for images up to a certain size, though I'm not sure exactly what the size is). The problem is that mail clients like Gmail would strip out your image data, but there's a simple workaround for that... just putting <b> and </b>
tags around your <img ...>
tag is all you need to do to keep it from getting stripped out. In order to get an image into your email, you need to get a base64 encoder into your project. There are several out there (mostly C though), but the simplest ObjC one I found was called NSData+Base64 by Matt Gallagher (I took the "+" out of the name after copying it in because it gave me problems). Copy the .h and .m files into your project and be sure to #import the .h file where you plan on using it. Then code like this will get an image into your email body...
- (void)createEmail {
//Create a string with HTML formatting for the email body
NSMutableString *emailBody = [[[NSMutableString alloc] initWithString:@"<html><body>"] retain];
//Add some text to it however you want
[emailBody appendString:@"<p>Some email body text can go here</p>"];
//Pick an image to insert
//This example would come from the main bundle, but your source can be elsewhere
UIImage *emailImage = [UIImage imageNamed:@"myImageName.png"];
//Convert the image into data
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(emailImage)];
//Create a base64 string representation of the data using NSData+Base64
NSString *base64String = [imageData base64EncodedString];
//Add the encoded string to the emailBody string
//Don't forget the "<b>" tags are required, the "<p>" tags are optional
[emailBody appendString:[NSString stringWithFormat:@"<p><b><img src='data:image/png;base64,%@'></b></p>",base64String]];
//You could repeat here with more text or images, otherwise
//close the HTML formatting
[emailBody appendString:@"</body></html>"];
NSLog(@"%@",emailBody);
//Create the mail composer window
MFMailComposeViewController *emailDialog = [[MFMailComposeViewController alloc] init];
emailDialog.mailComposeDelegate = self;
[emailDialog setSubject:@"My Inline Image Document"];
[emailDialog setMessageBody:emailBody isHTML:YES];
[self presentModalViewController:emailDialog animated:YES];
[emailDialog release];
[emailBody release];
}
I've tested this on the iPhone and sent lovely image embedded emails to myself on Yahoo, my personal website, and my MobileMe. I don't have a Gmail account, but the Yahoo worked perfectly, and every source I've found says that the bold-tags are all you need to make it work. Hope this helps all!
Related Topics
Zoom to Fit Current Location and Annotation on Map
Catch Any Error, Specially Unexpectedly Found Nil in Swift
Drag and Drop Image from Uicollectionview to Uiview
When to Call Activatesession() on Wcsession Object
Big O of Accessing a String with an Index in Swift 3.0
How to Create Apple Watchos5 Complication
Changing The Color of a Button in Swiftui on Tvos
Convert Optional String to Int in Swift
Swift, Error Exc_Breakpoint (Code=1, Subcode=0X100695474)
Swift - Getting Only Alphanumeric Characters from String
Swift Use Unicode Character in Localization.Strings
Checking Conforms Protocol with Associatedtype in Swift
Generic and (Early) Binding in Swift 1.2
Tap Gesture Not Working as Expected When Added to Uiview in Collectionview Cell