In App Email - MFMailComposeViewController - Error Message - objective-c

My code is as follows:
ViewController.m:
#import "ViewController.h"
#import "MyScene.h"
#import "MainMenu.h"
#import <MessageUI/MessageUI.h>
#implementation ViewController
- (IBAction)showMailPicker:(id)sender
{
// You must check that the current device can send email messages before you
// attempt to create an instance of MFMailComposeViewController. If the
// device can not send email messages,
// [[MFMailComposeViewController alloc] init] will return nil. Your app
// will crash when it calls -presentViewController:animated:completion: with
// a nil view controller.
if ([MFMailComposeViewController canSendMail])
// The device can send email.
{
[self displayMailComposerSheet];
}
else
// The device can not send email.
{
self.feedbackMsg.hidden = NO;
self.feedbackMsg.text = #"Device not configured to send mail.";
}
}
- (IBAction)showSMSPicker:(id)sender
{
// You must check that the current device can send SMS messages before you
// attempt to create an instance of MFMessageComposeViewController. If the
// device can not send SMS messages,
// [[MFMessageComposeViewController alloc] init] will return nil. Your app
// will crash when it calls -presentViewController:animated:completion: with
// a nil view controller.
if ([MFMessageComposeViewController canSendText])
// The device can send email.
{
[self displaySMSComposerSheet];
}
else
// The device can not send SMS.
{
self.feedbackMsg.hidden = NO;
self.feedbackMsg.text = #"Device not configured to send SMS.";
}
}
- (void)displayMailComposerSheet
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Support for Brick Smasher Extreme"];
// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:#"help.bricksx#gmail.com"];
//NSArray *ccRecipients = [NSArray arrayWithObjects:#"second#example.com", #"third#example.com", nil];
//NSArray *bccRecipients = [NSArray arrayWithObject:#"fourth#example.com"];
[picker setToRecipients:toRecipients];
//[picker setCcRecipients:ccRecipients];
//[picker setBccRecipients:bccRecipients];
// Attach an image to the email
//NSString *path = [[NSBundle mainBundle] pathForResource:#"rainy" ofType:#"jpg"];
//NSData *myData = [NSData dataWithContentsOfFile:path];
//[picker addAttachmentData:myData mimeType:#"image/jpeg" fileName:#"rainy"];
// Fill out the email body text
NSString *emailBody = #"Message:";
[picker setMessageBody:emailBody isHTML:YES];
//[self presentViewController:picker animated:YES completion:NULL];
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:picker
animated:YES
completion:nil];
}
- (void)mailComposeController:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
self.feedbackMsg.hidden = NO;
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
self.feedbackMsg.text = #"Result: Mail sending canceled";
break;
case MFMailComposeResultSaved:
self.feedbackMsg.text = #"Result: Mail saved";
break;
case MFMailComposeResultSent:
self.feedbackMsg.text = #"Result: Mail sent";
break;
case MFMailComposeResultFailed:
self.feedbackMsg.text = #"Result: Mail sending failed";
break;
default:
self.feedbackMsg.text = #"Result: Mail not sent";
break;
}
[self dismissViewControllerAnimated:YES completion:NULL];
}
#end
The error is: Warning: Attempt to present <MFMailComposeViewController: 0xbf95170> on <UIViewController: 0xbf78d10> whose view is not in the window hierarchy!
I'm trying to send email through my app. Using MFMailComposeViewController, it always gives an error (above). But when I use the SMS part, there is no problem at all.
Using: Xcode 5, iOS 7, iPhone Retina 4"

Your problem is likely here:
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:
First of all, you're already calling this from a ViewController, so you can just [self presentViewController:]. It does sound like maybe you're calling your displayMailComposerSheet before ViewController's view is visible (viewDidLoad or viewWillAppear maybe), which would raise the error you're seeing.

use
[self presentViewController:picker animated:YES completion:nil];
instead of
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:picker animated:YES completion:nil];

Related

Send mail to an array list recipients from a database in ObjectiveC

I am using ObjectiveC and I want to send an email to a list of email addresses that I have in a sqlite database. The email array hold the addresses that I want to send the mail to.
I show you my code
- (void)sendEmailButtonClicked: (id)sender {
// Email Subject
NSString *emailTitle = #"Test Email";
// Email Content
NSString *messageBody = #"iOS programming is so fun!";
// To address
NSArray *toRecipents = [NSArray arrayWithObject:emailArray];
NSLog(#"What are the emais %#",toRecipents);
MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = self;
[mc setSubject:emailTitle];
[mc setToRecipients:toRecipents];
[mc setMessageBody:messageBody isHTML:NO];
// Present mail view controller on screen
[self presentViewController:mc animated:YES completion:NULL];
}
- (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"Mail cancelled");
break;
case MFMailComposeResultSaved:
NSLog(#"Mail saved");
break;
case MFMailComposeResultSent:
NSLog(#"Mail sent");
break;
case MFMailComposeResultFailed:
NSLog(#"Mail sent failure: %#", [error localizedDescription]);
break;
default:
break;
}
// Close the Mail Interface
[self dismissViewControllerAnimated:YES completion:NULL];
}
I obtain this error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM mf_isLegalCommentedEmailAddress]: unrecognized selector sent to instance 0x78e5e180'
Anyone can help me please? Thank you so much!
First of all it should be:
NSArray *toRecipents = [NSArray arrayWithArray:emailArray];
But why not just do:
[mc setToRecipients:emailArray];
Assuming email array is a valid array object as we can't see from your code where/how you create it.
EDIT
You likely can't send an email from the simulator if there isn't an email account setup. Check for this with the following:
if ([MFMailComposeViewController canSendMail]) {
//Do your email stuff
}
else {
//Present an error etc ...
}
There's an issue with your array. This code works fine when sending to multiple recipients:
//Email
-(void)mailButton {
NSArray *emailArray = #[#"me#gmail.com", #"you#gmail.com", #"him#gmail.com", #"her#gmail.com", #"everyone#gmail.com"];
if ([MFMailComposeViewController canSendMail]) {
NSString *subject = #"Subject";
NSString *messageBody = [NSString stringWithFormat:#"Message Body"];
MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = self;
[mc setSubject:subject];
[mc setMessageBody:messageBody isHTML:NO];
[mc setToRecipients:emailArray];
[self presentViewController:mc animated:YES completion:NULL];
}
else {
UIAlertView *emailError = [[UIAlertView alloc] initWithTitle:#"Email Unavailable"
message:#"Sorry, were unable to find an email account on your device.\nPlease setup an account in your devices settings and try again."
delegate:self
cancelButtonTitle:#"Close"
otherButtonTitles:nil];
[emailError show];
}
}
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
switch (result) {
case MFMailComposeResultCancelled:
break;
case MFMailComposeResultSaved:
break;
case MFMailComposeResultSent:
break;
case MFMailComposeResultFailed:
break;
default:
break;
}
[self dismissViewControllerAnimated:YES completion:NULL];
}
toRecipents should be an array, which contains only one email address.
As below,
toRecipents = #[#"foo#example.com"];
If, you want to send email some people, you should use setCcRecipients method.

how to attach to an email a PDF file in Xcode5

I'm developing an app for Ipad (iOS7.1) in Xcode5 which opens an e-mail modal viewcontroller for sending email by using MFMailComposeViewController
I want to attach a PDF archive to my email
this is my code:
Functions.m:
#import <MessageUI/MessageUI.h>
#interface Functions()<MFMailComposeViewControllerDelegate>
#end
#implementation Functions
-(void)sendEmailInViewController:(UIViewController *)viewController {
NSString *emailTitle = #"Hello";
NSArray *toRecipents = [[NSArray alloc]initWithObjects:#"jesus#mymail.com", nil];
NSMutableString *messageBody =[[NSMutableString alloc]init];
[messageBody appendString:#"<p> </p><p> </p><p> </p><p><span style=\"font-size:14px;\"><span style=\"color: rgb(0, 0, 102);\"><span style=\"font-family: arial,helvetica,sans-serif;\"><strong>Jesus</strong><br />Gerente Select / Sucursal Santa Fe<br />Paseo de la Lidia No. 801 Piso 8 Mod. 162<br />Col. Lomas del Pedregal, C.P. 01292, México D.F.<br />Tel: + (55) 8728-0908. Ext. 12832<br />e-mail: jesus#mymail.com</span></span></span></p><p><span style=\"color:#000066;\"><span style=\"font-family: arial,helvetica,sans-serif;\"></span></span></p>"];
Class mailClass = (NSClassFromString(#"MFMailComposeViewController"));
if (mailClass != nil) {
MFMailComposeViewController * mailView = [[MFMailComposeViewController alloc] init];
mailView.mailComposeDelegate = self;
//Set the subject
[mailView setSubject:emailTitle];
//Set the mail body
[mailView setMessageBody:messageBody isHTML:YES];
[mailView setToRecipients:toRecipents];
NSData *pdfData = [NSData dataWithContentsOfFile:#"google.pdf"];
[mailView addAttachmentData:pdfData mimeType:#"application/pdf" fileName:#"google.pdf"];
//Display Email Composer
if([mailClass canSendMail]) {
[viewController presentViewController:mailView animated:YES completion:NULL];
}
}
}
- (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{
switch (result){
case MFMailComposeResultCancelled:NSLog(#"Mail cancelled"); break;
case MFMailComposeResultSaved: NSLog(#"Mail saved"); break;
case MFMailComposeResultSent: NSLog(#"Mail sent"); break;
case MFMailComposeResultFailed: NSLog(#"Mail sent failure: %#", [error localizedDescription]); break;
default: break;
}
// Close the Mail Interface
if (!app) { app = (AppDelegate *)[[UIApplication sharedApplication] delegate]; }
if (!currentSplitViewController) {
currentSplitViewController = (UISplitViewController *) app.window.rootViewController;
}
navController = [currentSplitViewController.viewControllers lastObject];
[[navController topViewController] dismissViewControllerAnimated:YES completion:NULL];
}
#end
on any viewController I call to my method this way:
- (IBAction)showEmail:(id)sender {
[functions sendEmailInViewController:self];
}
this is the screenshot of my mail:
it shows a logo of my pdf file, but when my message is sent, I open my inbox but I just find the signature, but anything attached for viewing... how to attach and send it correctly???
any help I'll appreciate
EDIT: this is the answer: I just had to add this
NSData *pdfData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"google" ofType:#"pdf"]];
[mailView addAttachmentData:pdfData mimeType:#"application/pdf" fileName:#"google"];
this is my result:
Sounds like you need to look at the "addAttachmentData:mimeType:fileName:" method of MFMailComposeViewController.
And using that method, you'll be able to add the raw NSData for whatever archive you want to send along. Just make certain you set the appropriate mime type (e.g. "application/zip") and file name (e.g. "MyArchive.zip").
For PDF files, the mime type would be "application/pdf" and you would use a filename like "google.pdf". Then all you would need to do is load a NSData object with the file data you want to attach.

ios: Application tried to present a nil modal view controller on target

I am developing an application,the requirement is to open email composer on a button click of UIAlertView.
message which is in message body of email is copied from UITextView. i am using following code snipt:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0)
{
// opening message composer
}
else
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Test mail"];
[picker setMessageBody:messageBody.text isHTML:YES];
[self presentViewController:picker animated:YES completion:NULL];
}
}
// mail compose delegate
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
but the issue is that i am getting error saying Application tried to present a nil modal view controller on target. how we can open default mail composer in ios 7?
As per Apple, You should check is MFMailComposeViewController are able to send your mail just before sending
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Test mail"];
[picker setMessageBody:messageBody.text isHTML:YES];
[self presentViewController:picker animated:YES completion:NULL];
}
Swift:
if MFMailComposeViewController.canSendMail() else {
// Send mail code
}
Ref : Apple Dev url
Swift 4 version
guard MFMailComposeViewController.canSendMail() else {
print("Mail services are not available")
return
}
sendEmail()
Forgetting Mail account configuration in device settings may also lead to this error. Re check whether a mail account is configured in your device or not.

Undeclared identifier 'mailComposeController'

Here is my .m code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *emailCell = [tableView cellForRowAtIndexPath:indexPath];
if ([emailCell.textLabel.text isEqualToString:#"Contact Developer"]) {
NSLog(#"Email button pressed...");
if([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"A Message from MobileTuts+"];
NSArray *toRecipients = [NSArray arrayWithObjects:#"fisrtMail#example.com", #"secondMail#example.com", nil];
[mailer setToRecipients:toRecipients];
NSString *emailBody = #"Have you seen the MobileTuts+ web site?";
[mailer setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:mailer animated:YES];
[mailer release];
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"Mail cancelled: you cancelled the operation and no email message was queued.");
break;
case MFMailComposeResultSaved:
NSLog(#"Mail saved: you saved the email message in the drafts folder.");
break;
case MFMailComposeResultSent:
NSLog(#"Mail send: the email message is queued in the outbox. It is ready to send.");
break;
case MFMailComposeResultFailed:
NSLog(#"Mail failed: the email message was not saved or queued, possibly due to an error.");
break;
default:
NSLog(#"Mail not sent.");
break;
}
// Remove the mail view
[self dismissModalViewControllerAnimated:YES];
}
}
else {
UIAlertView *emailAlert = [[UIAlertView alloc] initWithTitle:#"Error!"
message:#"Please make sure you have an email address configured in your Mail app."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[emailAlert show];
[emailAlert release];
}
}
}
I have imported everything correctly in .h and .m, but the email won't close... I have tried as suggested on Stack Overflow to fiddle with the mailer.mailComposeDelegate = self; but I am still getting an undeclared identifier error. How do I fix this? Thanks.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
Move this function out of the tableview delegate method. You should learn some basics. You cannot have a method within another method. If you need then you can call the method by [self callingFunctionName];
In you case,
if ([emailCell.textLabel.text isEqualToString:#"Contact Developer"]) {
NSLog(#"Email button pressed...");
[self sendEmail];
}
-(void)sendEmail{
if([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"A Message from MobileTuts+"];
NSArray *toRecipients = [NSArray arrayWithObjects:#"fisrtMail#example.com", #"secondMail#example.com", nil];
[mailer setToRecipients:toRecipients];
NSString *emailBody = #"Have you seen the MobileTuts+ web site?";
[mailer setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:mailer animated:YES];
[mailer release];
}
}
This will open the mail composer. When you send, cancel or save the mail, the delegate function
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
will automatically be called.

ipad mail composer application to send a image to another address

i done a sample ipad mail composer application to send a image to another address.so i wrote the following code:
#import <messageUI/MFMailComposeViewController.h>
//to compose mail
-(IBAction)composeMail{
if([self validateImageView]){
[self sendSelectedImage];
}
else{
[self showAlert];
}
}
//to validate image view
-(BOOL)validateImageView{
if(selectedImageView.image){
return YES;
}
else{
return NO;
}
}
//to send selected image
-(void)sendSelectedImage{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
#try {
picker.mailComposeDelegate = self;
[picker setSubject:#"Hello from Triassic!"];
// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:#"shamsudheen#triassicsolutions.com"];
NSArray *ccRecipients = [NSArray arrayWithObjects:#"shamsudheen#triassicsolutions.com", #"shamsudheen#triassicsolutions.com", nil];
NSArray *bccRecipients = [NSArray arrayWithObject:#"shamsudheen#triassicsolutions.com"];
[picker setToRecipients:toRecipients];
[picker setCcRecipients:ccRecipients];
[picker setBccRecipients:bccRecipients];
// Attach an image to the email
NSData *myData = UIImagePNGRepresentation(selectedImageView.image);
[picker addAttachmentData:myData mimeType:#"image/jpeg" fileName:#"rainy"];
// Fill out the email body text
NSString *emailBody = #"It is raining in Trivandrum!";
[picker setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:picker animated:YES];
}
#catch (NSException * ex) {
NSLog([NSString stringWithFormat:#"%#",ex]);
}
#finally {
[picker release];
}
}
//to show a alert box
-(void)showAlert{
UIAlertView *alertView;
alertView = [[UIAlertView alloc] initWithTitle:#"Please select a image from PhotoAlbums!" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"Continue", nil];
[alertView show];
[alertView release];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation==UIInterfaceOrientationLandscapeRight || interfaceOrientation==UIInterfaceOrientationLandscapeLeft);
}
#pragma mark -
#pragma mark Dismiss Mail/SMS view controller
// Dismisses the email composition interface when users tap Cancel or Send. Proceeds to update the
// message field with the result of the operation.
- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
#try {
feedbackMsg.hidden = NO;
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
feedbackMsg.text = #"Mail sending canceled";
break;
case MFMailComposeResultSaved:
feedbackMsg.text = #"Mail saved";
break;
case MFMailComposeResultSent:
feedbackMsg.text = #"Mail sent";
break;
case MFMailComposeResultFailed:
feedbackMsg.text = #"Mail sending failed";
break;
default:
feedbackMsg.text = #"Mail not sent";
break;
}
}
#catch (NSException * ex) {
NSLog([NSString stringWithFormat:#"%#",ex]);
}
#finally {
[self dismissModalViewControllerAnimated:YES];
}
}
so when compose button clicks it will show a popup with the entered mail address and with all the details.
it showing the result send process is done successfully.but i am not getting any mail to shamsudheen#triassicsolutions.com.may i know what is the mistake i done.can i send a mail through this to another email by entering the popup through the address section.i think the compose method works when popup is loading.then how can i send a mail to address that in entered in the displayed popup.it not working fine ..may i know whats the mistake i done
In Simulator you cannot send the mail because If you want to send a mail to another person first you have to set your maildetails(you have to login to your account) in the account settings in the Device. But that feature is not exists in the Simulator.That's why you cannot send the email from Simulator.