I am using MFMailComposeViewController in my application to compose a feedback E-Mail. The MFMailComposeViewController gets displayed, but can't be closed.
Method used to open the MFMailComposeViewController modal window:
-(IBAction) feedbackBtnClicked:(id)sender {
// Dismiss the Old View Controller
[self dismissViewControllerAnimated:NO completion:NULL];
// Present the New View Controller
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
mail.mailComposeDelegate = self;
[mail setSubject:#"Sample Subject"];
[mail setMessageBody:#"Here is some main text in the email!" isHTML:NO];
[mail setToRecipients:#[#"example#mail.com"]];
[self presentViewController:mail animated:YES completion:NULL];
}
else
{
NSLog(#"This device cannot send email");
}
}
Here is what happens, when clicking on the buttons:
Senden (Send) - The E-Mail gets sent, but the modal window stays open; clicking on that button multiple times results in sending multiple E-Mails without the modal window ever getting closed.
Abbrechen (Cancel) - Nothing happens
How to dismiss make sure the MFMailComposeViewController gets dismissed after clicking on those buttons?
You need to implement the MFMailComposeViewControllerDelegate method mailComposeController:didFinishWithResult:error:, and dismiss the mail view controller…
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller
didFinishWithResult:(MessageComposeResult)result
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
I have a some kind of action sheet UIView which calls MFMailComposeViewController after tapping a button in it, the MFMailComposeViewController gets called and presented successfully, but it doesn't dismiss when the I tap Cancel and sometimes crashes, I know this is a known problem, but I have tried all the known fixes but it doesn't work for me. That's my code:
SendFeedback.h:
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#interface SendFeedback : UIView <UITableViewDelegate, UITableViewDataSource, MFMailComposeViewControllerDelegate, UINavigationControllerDelegate>
//Useless code to the problem.
#property (nonatomic, retain) MFMailComposeViewController *feedBackComposer;
#end
SendFeedback.m:
- (void)baseInit
{
//Useless code to the problem.
feedBackComposer = [[MFMailComposeViewController alloc] init];
[feedBackComposer setMailComposeDelegate:self];
[feedBackComposer setToRecipients:[NSArray arrayWithObject:#"info#getibox.com"]];
[feedBackComposer setMessageBody:#"" isHTML:NO];
[feedBackComposer setSubject:#"What I Love About iBox"];
}
And to call the composer:
- (void)sendFeedbackComposer
{
[self.window.rootViewController presentViewController:feedBackComposer animated:YES completion:nil];
}
To dismiss it:
- (void)mailComposeController:(MFMailComposeViewController *)feedBackComposer didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
//This method doesn't get called.
[self.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
NSLog(#"Error: %#", error);
}
EDIT: So, all the answers provided in this question were correct, and it was all my bad. What I wanted to do is: I had a UINavigationController which includes a UITableView one of the cells in that view should trigger an action sheet which is a UITableView by adding it as a subview, just like the previous one, this view also includes cells and one of them will do an action and it is calling an MFMailComposeViewController, which gets called but doesn't dismiss successfully even though I had its delegate set up and all the methods correct, the cause of the problem was the way of calling the MFMailComposeController, I first removed from super view that little UITableView then presented the MFMailComposeController, so when I dismissed the mail composer it crashed without even giving a result, which made me confuse the cause of the crash with the delegate method, fool me.
Here's the code:
- (void)removeView
{
if (self) {
[UIView animateWithDuration:0.3
animations:^{backgroundView.alpha = 0;}
completion:^(BOOL finished){
[UIView animateWithDuration:.3
animations:^{self.frame = CGRectMake(0, 568, 320, 568);}
completion:^(BOOL finished){[self removeFromSuperview];}];
}];
}
}
- (void)sendFeedbackComposer
{
feedBackComposer = [[MFMailComposeViewController alloc] init];
[feedBackComposer setMailComposeDelegate:self];
[feedBackComposer setToRecipients:[NSArray arrayWithObject:#"info#getibox.com"]];
[feedBackComposer setMessageBody:#"" isHTML:NO];
[feedBackComposer setSubject:#"What I Love About iBox"];
[self.window.rootViewController presentViewController:self.feedBackComposer animated:YES completion:nil];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row) {
case 2: //That's the index of the MailComposer caller.
[self removeView];
[self sendFeedbackComposer];
break;
case 6:
[self removeView];
break;
default:
break;
}
}
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
[feedBackComposer.presentingViewController dismissViewControllerAnimated:YES completion:nil];
NSLog(#"Error: %#", error);
}
Thanks to Stefan Atanasov, Jim, and Vitaly S.
Are you sure that delegate method isn't called? I made a test and it's called, but to dismiss mail composer use such code:
[feedBackComposer dismissViewControllerAnimated: YES completion: nil];
Also it's really strange to implement delegates in view implementation, not in view controller
To add something to Vitaly S.'s answer (due to lack of reputation I can't comment directly on it, sorry) - the delegate method is called, so the problem is the dismissal. You can try this:
[feedBackComposer.presentingViewController dismissViewControllerAnimated: YES completion: nil];
The delegate methods need to be called from the viewController, not from within the UIView.
Your view controller that calls the UIView will have your delegates
<UITableViewDelegate, UITableViewDataSource, MFMailComposeViewControllerDelegate, UINavigationControllerDelegate>
within it's header file.
You need to make a delegate method to pass information from the UIView to the controller, which will in turn call the mail and table delegate methods.
Here is a link to a question that demonstrates how to use a delegate protocol to trigger a method in the view controller from the UIView.
Trigger a method in UIViewController from its View
Hope this helps, Jim
you need to check is it device is configure to send mail by checking MFMailComposeViewController is avail to respond or not.
if([MFMailComposeViewController canSendMail]){
//your code
}
My app has a common class that displays an actionSheet whenever "Contact Us" is clicked from any one of the many NIBs.
If the user chooses "Email Us" from the actionSheet popup, I'd like to call the email methods from the same common class. After researching I implemented this:
-(void)SendEmail {
rootViewController = (UIViewController*)
[(AppDelegate*)[[UIApplication sharedApplication] delegate] viewController];
// compose
MFMailComposeViewController* controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = rootViewController;
//format message
NSArray *recipientsArray = [[NSArray alloc] initWithObjects:#"support#somename.com", nil];
[controller setToRecipients:recipientsArray];
[controller setSubject:[NSString stringWithFormat:#"A question about %#",string]];
[controller setMessageBody:outputMutString isHTML:YES];
//send
if (controller) [rootViewController presentModalViewController:controller animated:YES];
}
//didFinishWithResult
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error;{
if (result == MFMailComposeResultSent) {
}
[rootViewController dismissModalViewControllerAnimated:YES];
}
This will launch a new email, however:
The didFinishWithResult doesn't work as the modal view is not removed either after sending the email or pressing the Cancel button
I am getting this warning: assigning to 'id' from incompatible type 'UIViewController *__strong'
controller.mailComposeDelegate = rootViewController;
Help appreciated.
You need to set your rootViewController as adopting the delegate MFMailComposeViewControllerDelegate.
i.e. in your RootViewController.h file, add that part to the interface declaration so that it looks similar to:
#interface RootViewController : UIViewController <MFMailComposeViewControllerDelegate>
I am very new to iPhone development.
In my app, I want to send email using MFMailComposeViewController while clicking a button.
How can I achieve this?
I used the code below.
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
[controller setSubject:#"Email App"];
[controller setMessageBody:#"Sample email app" isHTML:NO];
[self presentModalViewController:controller animated:YES]; // App crash in this line.
[controller release];
It is showing this warning:
'ImportingDocumentAppDelegate' may not respond to '-presentModalViewController:animated:'.
Thanks.....
#Arun presentModalViewController is the method of UIViewController so you cann't call it on app delegate instance. Add a UIViewController's view to your window then call this method on that view controller.
Your error message indicates that you are telling your app delegate to present the view. You need to call this function on a UIViewController.
I have a view with a few text boxes and labels. I'd like to email the view containing this information to either a contact list or just a text box with an email address in it.
I can't get the view to email. I'd like to send the whole page without having to somehow list every text box. How do I email the view with this code:
[controller setMessageBody:textBoxesAndInfo isHTML:YES];
-(IBAction)sendMail {
// create an instance of MFMailComposeViewController for sending an e-mail
MFMailComposeViewController *controller =
[[MFMailComposeViewController alloc] init];
// set controller's delegate to this object
controller.mailComposeDelegate = self;
[controller setToRecipients:#[#"hello#example.com"]];
[controller setSubject:#"Subject"];
[controller setMessageBody:textBoxesAndInfo isHTML:YES];
// show the MFMailComposeViewController
[self presentModalViewController:controller animated:YES];
}
// called when the user finishes sending an e-mail
- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[self dismissModalViewControllerAnimated:YES];
}
Remember to include the MessageUI framework.