when I press the sendMail button, it will go to the mail button, but when I hit send or cancel it will not take me back to my application. Any suggestions?
-(IBAction)sendMail {
MFMailComposeViewController *mailComposer = [[[MFMailComposeViewController alloc] init] autorelease] ;
if ([MFMailComposeViewController canSendMail]) {
[mailComposer setToRecipients:nil];
[mailComposer setSubject:nil];
[mailComposer setMessageBody:#"Default text" isHTML:NO];
[self presentModalViewController:mailComposer animated:YES];
}
}
You need to set a delegate (generally the same view controller that presented the MFMailComposeViewController). Then when the user taps the Save or Cancel button the MFMailComposeViewController will call -mailComposeController:didFinishWithResult:error on the delegate. So set yourself as the delegate and define the following method:
#pragma mark -
#pragma mark MessageUI Delegate Methods
- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result
error:(NSError*)error {
[controller dismissModalViewControllerAnimated:YES];
}
Add the following line below your mail composer initialization
mailComposer.mailComposeDelegate = self;//very important if you want feedbacks on what the user did with your email sheet.
Then implement the delegate method as Kenny suggested. You can use this method to take custom actions.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
{
//Do something, If you need to
}
break;
default:
break;
}
[self dismissModalViewControllerAnimated:YES];
}
Remember to conform to the delegate by adding
#interface YourViewController : UIViewController <MFMailComposeViewControllerDelegate> { }
If you are still having trouble, You may visit the following tutorial where everything nicely explained:
http://blog.mugunthkumar.com/coding/iphone-tutorial-in-app-email/
This wonderful line:
mailComposer.mailComposeDelegate = self;
is what made it happen for days without knowing that was what went wrong.
And do not forget them:
# import <UIKit/UIKit.h>
# import <MessageUI/MessageUI.h>
# import <MessageUI/MFMailComposeViewController.h>
In addition to importing the MessageUI.framework in the project.
Verified in IOS5
Related
I'm in a bit of trouble, I've spent half a day working onto this issue I have with no major results after all deprecations in iOS6 and other issues. This iOS app, has a send email option when after pushing a button, the app takes a screenshot of my WebView, attaches it to the email and from there, have the normal options to cancel or send the email and return to the app. I made it to the part where the email pops up, and actually 2 issues here: one is that after pressing either cancel or send, the email view won't dismiss, the app is stuck in the email view. And the second issue I have is the image that gets attached is just a tiny icon (blue with an question mark just like it is not recognised or is missing...
Can someone please point me in the right direction as I feel like I'm going crazy. I've researched the net backwards and forwards with no luck. Many similar threads but different issues not exactly related to my issues unfortunately. Sorry, and thanks in advance.
Here is my code:
// in my LiveView.h file
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <MessageUI/MessageUI.h>
#import "CamSetup.h"
#interface LiveView : UIViewController < MFMailComposeViewControllerDelegate , ADBannerViewDelegate >
....
-(IBAction)shotAndSend:(id)sender;
// in my LiveView.m file:
- (void)mailComposer:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
NSLog(#"in didFinishWithResult:");
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"cancelled");
break;
case MFMailComposeResultSaved:
NSLog(#"saved");
break;
case MFMailComposeResultSent:
NSLog(#"sent");
break;
case MFMailComposeResultFailed: {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Error sending mail",#"Error sending mail")
message:[error localizedDescription] delegate:nil
cancelButtonTitle:NSLocalizedString(#"test",#"test")
otherButtonTitles:nil];
[alert show];
break;
}
default: break;
}
[self dismissViewControllerAnimated:NO completion:Nil];
}
-(IBAction)shotAndSend:(id)sender
{
UIGraphicsBeginImageContext(_myWebView.frame.size);
[_myWebView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * imageData = UIImageJPEGRepresentation (image, 2.1);
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController * mailComposer = [[MFMailComposeViewController alloc] init];
mailComposer.mailComposeDelegate = self;
[mailComposer addAttachmentData:imageData mimeType:#"image/jpeg" fileName:#"attachment.jpeg"];
[mailComposer setSubject:#"A screenshot from my App"];
[mailComposer setToRecipients:[NSArray arrayWithObjects:#"123#yexample.com", nil]];
[self presentViewController: mailComposer animated:YES completion:NULL];
}
}
Your code isn't working because you have the wrong method. You have:
- (void)mailComposer:(MFMailComposeViewController *)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
but it should be:
- (void)mailComposeController:(MFMailComposeViewController*)controller
didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
You need a delegate of your view that will dismiss that view for you. The fact that you don't see the log indicate you that you haven't implemented correctly the delegation protocol. Take a look at some example in the apple documentation.
I am trying to create a class who will be responsible to send emails using MFMailComposeViewController so i can use this methods from differences views controls in my app.
This class is called apoio.
In this class have the method bellow.
-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico {
if (![MFMailComposeViewController canSendMail]) {
// show message box for user that SMS cannot be sent
} else {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Dashboard"];
[picker addAttachmentData:_pdfGrafico mimeType:#"application/pdf" fileName:#"grafico.pdf"];
NSString *emailBody = #"Anexando gráfico";
[picker setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:picker animated:YES];
}
}
I have another view controller who calls the apoio method when the user clicks on email button. It is this code bellow
-(IBAction) enviarGraficoPorEmail {
Apoio *apoio = [[Apoio alloc] init];
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer]];
}
But i don't know why, the email view doesn't appear. The method is called correct because i debuged and so on.
If i copy the code from apoio method to enviarGraficoPorEmail method, everything works perfect.
But i don't want to do this, beucase ill send emails from others views controller.
What am i doing wrong ??
You could do it a couple of different ways.
Option 1: Pass the calling view controller as a parameter to the class method
-(IBAction) enviarGraficoPorEmail {
Apoio *apoio = [[Apoio alloc] init];
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer] callingController:self];
}
-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico callingController:(UIViewController*)_callingController {
...
[_callingController presentModalViewController:picker animated:YES];
...
}
Option 2: Add a class variable for the calling view controller
-(IBAction) enviarGraficoPorEmail {
Apoio *apoio = [[Apoio alloc] init];
apoio.callingController = self;
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer]];
}
-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico callingController:(UIViewController*)_callingController {
...
[callingController presentModalViewController:picker animated:YES];
...
}
Then you'd add callingController to your class as a retain property, initialize it to nil, and release it in dealloc.
Option #1 is probably the better approach for your needs.
Thanks a lot!. It is now working but i still have one problem.
I have the method on my generic class who is supposed to be responsible to hide the mailController.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
case MFMailComposeResultCancelled:
break;
case MFMailComposeResultSaved:
break;
case MFMailComposeResultSent:
// FAILS
[self.parentViewController dismissModalViewControllerAnimated:YES];
break;
case MFMailComposeResultFailed:
break;
default:
break;
}
[self dismissModalViewControllerAnimated:YES];
}
In the method that creates the mailController have the property
picker.mailComposeDelegate = self;
I tried to change to
picker.mailComposeDelegate = _callingController.self;
I set the MFMailComposeViewControllerDelegate on my generic class already.
But it only works when i copy the method didFinishWithResult and put it on the origin controller, what is not my intention, because i want to put all this code on a generic class.
What am i doing wrong ??
Ok, this is an answer to your second question (which you posted as an answer to your first question).
Here's how I would set it all up:
In your calling view controller .h file:
#interface MyViewController : UIViewController <MyMailDelegate> {
Apoio *apoio;
}
In your calling view controller .m file:
-(IBAction) enviarGraficoPorEmail {
apoio = [[Apoio alloc] init];
apoio.callingController = self;
[apoio enviarGraficoPorEmail:[barChart dataForPDFRepresentationOfLayer]];
}
-(void) enviarCompleto {
//do whatever here after send email completes
[apoio release];
}
In your Apoio .h file
#protocol MyMailDelegate
#required
-(void) enviarCompleto;
#end
#interface OfferObject : NSObject {
UIViewController <MyMailDelegate> *callingController;
}
#property (nonatomic, retain) UIViewController <MyMailDelegate> *callingController;
In your Apoio .m file
-(void) enviarGraficoPorEmail: (NSData*) _pdfGrafico callingController:(UIViewController*)_callingController {
...
[callingController presentModalViewController:picker animated:YES];
...
}
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
switch (result)
{
...
}
[callingController dismissModalViewControllerAnimated:YES];
[callingController enviarCompleto];
}
Then don't forget to do this on init:
callingController = nil;
And on dealloc:
[callingController release];
Also, don't forget your most important step: up vote both my answers :)
You need to call [self presentModalViewController:picker animated:YES];
from a UIViewController class then it will show you email composer, you can do this, whenever you call from some view controller you can pass its reference and you can change the above line as this
[callingController presentModalViewController:picker animated:YES];
I am having difficulties adding the ability for a user to send a support email to myself (the maker of said app). I have gotten it work almost perfectly however the view doesn't close when you click cancel, or when you click send. Thanks for the help!
Here is the code:
MFMailComposeViewController *mail = [[[MFMailComposeViewController alloc] init] autorelease];
mail.mailComposeDelegate = self;
[mail setToRecipients:[NSArray arrayWithObject:#"support#lindahlstudios.com"]];
[mail setSubject:#"Fraction Calculator Lite Support"];
[self presentModalViewController:mail animated:YES];
You're setting self to be the MFMailComposeViewController's delegate. In mailComposeController:didFinishWithResult:error: be sure to call
[self dismissModalViewControllerAnimated:YES];
like so:
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
[self dismissModalViewControllerAnimated:YES];
}
You need to implement the delegate method from MFMailComposeViewControllerDelegate.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[self dismissModalViewControllerAnimated:YES];
}
I'm having difficulties closing an email message that I have raised.
The email opens nicely, but once it is opened it will not close as the mailComposeController:mailer didFinishWithResult:result error:error handler never gets invoked.
As far as I can tell I have all the bits in place to be able to do this.
Anyone any ideas of what I can look at?
Here is how I raise the email:
-(IBAction)emailButtonPressed
{
NSString *text = #"My Email Text";
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.delegate = self;
[mailer setSubject:#"Note"];
[mailer setMessageBody:text isHTML:NO];
[self presentModalViewController:mailer animated:YES];
[mailer release];
}
and later in the class I have this code to handle the close (but it never gets called):
-(void)mailComposeController:(MFMailComposeViewController *)mailer didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
[self becomeFirstResponder];
[mailer dismissModalViewControllerAnimated:YES];
}
My header file is defined as:
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>
#interface myViewController : UIViewController <UIActionSheetDelegate, UIAlertViewDelegate, MFMailComposeViewControllerDelegate, UINavigationControllerDelegate>
Thanks
Iphaaw
You are setting the delegate wrong, the delegate property in MFMailComposeViewController is called mailComposeDelegate, so it should be:
mailer.mailComposeDelegate = self;
Another possible error I can see is calling dismissModalViewControllerAnimated: on mailer - you should send this message to the view controller who presented the mail interface - self in this case:
[self dismissModalViewControllerAnimated:YES];
I wrote "possible error" because it might actually work if iOS routes the message through responder chain, anyway - the documentation says it should be send to presenter.
I am trying to send mail using MFMailComposeViewController. Everything works, except that mails do not get sent, and I always get MFMailComposeResultFailed.
Any pointers? I am NOT using the simulator, and sending mail does work from my device. I do have a connection (testing via Reachability), and [MFMailComposeViewController canSendMail] returns YES.
No compiler warnings in the project, no crashes...
It was a bug in IOS4.
I had both an Exchange mail account and an old, inactive IMAP account on my phone. Apparently, that leads to problems with iOS4. The mails actually were stuck in the outbox. Once I removed the inactive IMAP account, everything worked as expected.
Some readers might be facing this problem:
Make sure you implement the <MFMailComposeViewControllerDelegate> protocol
Here's the code:
// in TestViewController.h
#interface TestViewController : UIViewController<MFMailComposeViewControllerDelegate>
#end
// in TestViewController.m
#interface TestViewController ()
#end
#implementation
- (void) compose {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Hello there"];
[picker setToRecipients:#[]];
// Fill out the email body text
NSString *emailBody = #"Hello, sending a message from my app";
[picker setMessageBody:emailBody isHTML:NO];
// use this function. presentModalViewController:... is deprecated
[self presentViewController:picker animated:YES completion:nil];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
It's difficult to tell without seeing a code snippet, however you should check the following:
1) you have correctly set the MFMailComposeViewController's delegate and implemented its delegate methods;
2) you have set the mail subject using setSubject:
3) you have set the message body using setMessageBody:isHTML:
and optionally set an attach using addAttachmentData:mimeType:fileName:
4) you have presented to the user your mail compose view controller using something like
[self presentModalViewController:mcvc animated:YES];
Hope this helps.