I want to send a mail from my application. I am doing my first steps with SWIFT and i have stuck at a point. I want to press a button and open up the mail. Can you please tell me how to do the button connection? I think it should be an action but I don't know where to put it on the code
import UIKit
import MessageUI
class ViewController: UIViewController, MFMailComposeViewControllerDelegate {
func sendEmail() {
let mailVC = MFMailComposeViewController()
mailVC.mailComposeDelegate = self
mailVC.setToRecipients([])
mailVC.setSubject("Subject for email")
mailVC.setMessageBody("Email message string", isHTML: false)
presentViewController(mailVC, animated: true, completion: nil)
}
// MARK: - Email Delegate
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Import library first:
import MessageUI
set delegate like:
MFMailComposeViewControllerDelegate
Write pretty code:
#IBAction func buttonHandlerSendEmail(_ sender: Any) {
let mailComposeViewController = configureMailComposer()
if MFMailComposeViewController.canSendMail(){
self.present(mailComposeViewController, animated: true, completion: nil)
}else{
print("Can't send email")
}
}
func configureMailComposer() -> MFMailComposeViewController{
let mailComposeVC = MFMailComposeViewController()
mailComposeVC.mailComposeDelegate = self
mailComposeVC.setToRecipients([self.textFieldTo.text!])
mailComposeVC.setSubject(self.textFieldSubject.text!)
mailComposeVC.setMessageBody(self.textViewBody.text!, isHTML: false)
return mailComposeVC
}
Also write delegate method like:
//MARK: - MFMail compose method
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
100% working and tested
change sendEmail like this:
#IBAction func sendEmail(sender: AnyObject) {
let mailVC = MFMailComposeViewController()
mailVC.mailComposeDelegate = self
mailVC.setToRecipients([])
mailVC.setSubject("Subject for email")
mailVC.setMessageBody("Email message string", isHTML: false)
presentViewController(mailVC, animated: true, completion: nil)
}
and connect in Interface builder your button to this action
Swift 3
let composer = MFMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
composer.mailComposeDelegate = self
composer.setToRecipients(["Email1", "Email2"])
composer.setSubject("Test Mail")
composer.setMessageBody("Text Body", isHTML: false)
present(composer, animated: true, completion: nil)
}
Delegate method
class SendMailViewController: MFMailComposeViewControllerDelegate {
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
dismiss(animated: true, completion: nil)
}
}
To send mail, generally MFMailComposer is used. It can be tested on device as it doesn't work on iOS simulator.
For testing whether mail service is available or not, use below function,
if !MFMailComposeViewController.canSendMail() {
print("Mail services are not available")
return
}
and to send mail, use below code in your function or action of button.
let composeVC = MFMailComposeViewController()
composeVC.mailComposeDelegate = self
// Configure the fields of the interface.
composeVC.setToRecipients(["email_address#example.com"])
composeVC.setSubject("Hello World!")
composeVC.setMessageBody("Hello from iOS!", isHTML: false)
// Present the view controller modally.
self.presentViewController(composeVC, animated: true, completion: nil)
There is delegate method on completion of sending mail which can be defined as below shown,
func mailComposeController(controller: MFMailComposeViewController,
didFinishWithResult result: MFMailComposeResult, error: NSError?) {
// Check the result or perform other tasks.
// Dismiss the mail compose view controller.
controller.dismissViewControllerAnimated(true, completion: nil)
}
to Anton Platonov add: import MessageUI at the begging of your source file, and when you declaring class for your view controller add protocol: class FirstVC: UIViewController, MFMailComposeViewControllerDelegate{
Related
I'm using MFMailComposeViewController in a view controller with the following code:
if !MFMailComposeViewController.canSendMail() {
return
}
let mailComposeViewController = MFMailComposeViewController()
mailComposeViewController.mailComposeDelegate = self
present(mailComposeViewController, animated: true)
And:
extension MyViewController : MFMailComposeViewControllerDelegate {
private func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
}
The MFMailComposeViewController shows as expected, but has the following behavior:
Cancel button either does nothing (if the message has not been edited) or shows the "Delete Draft"/"Save Draft" action sheet, none of the options of which dismiss the MFMailComposeViewController
The send button does nothing, whether or not it's disabled (no recipient set) or enabled (recipient set)
The view can be dismissed by swiping it down (new iOS 13 modal behavior)
This is Xcode 11.2, iOS 13.2, Swift 4.
How can I fix this?
In this code
extension MyViewController : MFMailComposeViewControllerDelegate {
private func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
}
Delete the keyword private. It hides the method from Cocoa so that it will never be called.
Make sure that your class MyViewController is not a subclass of MFMailComposeViewController.
You should:
Create a UIViewController subclass (class MailViewController: UIViewController)
Add MFMailComposeViewController.
MailViewController: MFMailComposeViewControllerDelegate
Or:
Configure MFMailComposeViewController() directly from another UIViewController. For example:
let mailComposeVC = MFMailComposeViewController()
mailComposeVC.mailComposeDelegate = self
mailComposeVC.setToRecipients([recipient])
mailComposeVC.setSubject(subject)
mailComposeVC.setMessageBody(body, isHTML: false)
present(mailComposeVC, animated: true, completion: nil)
Hi want want to make a refer a friend through SMS I write the following code. If user is pick on that open the SMS with text but it don't cancel again user will unable go back to app.
if indexPath.item == 1
{
//SMS
if MFMessageComposeViewController.canSendText() {
let urlToShare = self.referalmodeldata[0].referralCodeOnly
controller1.body = "Hey I just gave an Awesome Assessment on App you can also try it. I scored , Try to beat my score \(String(describing: urlToShare))"
controller1.messageComposeDelegate = self as? MFMessageComposeViewControllerDelegate
self.present(controller1, animated: true, completion: nil)
}
}
You haven't implemented MFMessageComposeViewControllerDelegate correctly in your code.
First of all you need to confirm MFMessageComposeViewControllerDelegate with your UIViewController as shown below:
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate {
Next thing is you need add it's delegate method as shown below:
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
self.dismiss(animated: true, completion: nil)
}
Then you need to replace
controller1.messageComposeDelegate = self as? MFMessageComposeViewControllerDelegate
with
controller1.messageComposeDelegate = self
Demo code will be:
import UIKit
import MessageUI
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate {
#IBAction func sendText(_ sender: Any) {
if (MFMessageComposeViewController.canSendText()) {
let controller = MFMessageComposeViewController()
controller.body = "Message Body"
controller.messageComposeDelegate = self
self.present(controller, animated: true, completion: nil)
}
}
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
self.dismiss(animated: true, completion: nil)
}
}
I have a DataHandler object that shows a MFMailComposeViewController onto different ViewControllers when instantiated.
For example, in a class, I have an IBAction that emails data and calls DataHandler in order to do so:
#IBAction func exportData(_ sender: Any) {
let dh = DataHandler()
dh.sendEmail(vc: self)
}
DataHandler then does this:
func configureEmail() -> MFMailComposeViewController{
let mailComposerVC = MFMailComposeViewController()
let dataHandler = DataHandler()
let data = dataHandler.getData(fileName: file!)
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients([emailAddr!])
mailComposerVC.setSubject("blah!")
mailComposerVC.addAttachmentData(data as Data, mimeType: "text/csv", fileName: "file.csv")
return mailComposerVC
}
func sendEmail(vc: UIViewController){
if MFMailComposeViewController.canSendMail() {
let emailClient = configureEmail()
vc.show(emailClient, sender: vc)
}
else{
print("Unable to send emails")
}
}
I'm able to send emails, however, am unable to dismiss the view controller after it's sent. I've already inserted this in DataHandler
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
// Dismiss the mail compose view controller.
controller.dismiss(animated: true, completion: nil)
}
I have scoured the internet for solutions and am at my wits' end. Please help! :)
Edit 1:
Changed controller.dismiss(animated: true, completion: nil) to self.dismiss(animated: true, completion: nil)
You need to set the delegate:
mailComposerVC.mailComposertDelegate = self
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?)
was defined outside of the scope of the IBAction. So the DataHandler object that was needed to dismiss the MFMailComposeViewController was not in the same scope of the dismiss function. The solution was to declare the DataHandler object as a variable of the class that was calling the DataHandler functions.
I am just learning to code and I am trying to create a simple code to send a message on IOS. I have made sure to import the MessageUI framework. When I run it on my simulator, it fails and shows THREAD 1 : SIGNAL SIGABRT. I apologize profusely if it's just a small mistake, as I often do such errors and don't wish to waste anyone's time. Here is my code:
import UIKit
import MessageUI
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate {
#IBOutlet weak var messageLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func SendSMS(sender: AnyObject) {
let messageVC = MFMessageComposeViewController()
messageVC.recipients = ["5146276051"]
messageVC.body = messageLabel.text
messageVC.messageComposeDelegate = self
self.presentViewController(messageVC, animated: true, completion: nil)
}
func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) {
switch (result.rawValue) {
case MessageComposeResultCancelled.rawValue:
print("Message was cancelled")
self.dismissViewControllerAnimated(true, completion: nil)
case MessageComposeResultFailed.rawValue:
print("Message has failed")
self.dismissViewControllerAnimated(true, completion: nil)
case MessageComposeResultSent.rawValue:
print("Message was sent")
self.dismissViewControllerAnimated(true, completion: nil)
default:
break
}
}
}
Thank you very much!
Hi try to use your code on physical device, it should work.
BTW in your code please add check whether device support sending messages:
#IBAction func SendSMS(sender: AnyObject) {
//Checking whether device support message sending
if (MFMessageComposeViewController.canSendText() == false) { return }
let messageVC = MFMessageComposeViewController()
messageVC.recipients = ["5146276051"]
messageVC.body = messageLabel.text
messageVC.messageComposeDelegate = self
self.presentViewController(messageVC, animated: true, completion: nil)
}
in that way you will avoid e.g. crashes on simulator.
I'm using Xcode 8 to build an application for iPhone.My simple app has an button. When user tap on this button, messageComposeViewController is called and with phone number and message content filled.The message went through successfully when I clicked on Send button.The problem is MessageComposeViewController is showing only once.After the message sent, when I tapped on the button to call it, a black screen showed up instead of the message composer.My code is attached below. I appreciate any help.
import UIKit
import MessageUI
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate {
let msg = MFMessageComposeViewController()
#IBOutlet weak var coordinate_label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func sendMessage(_ sender: AnyObject) {
self.msg.body = "Message Content"
self.msg.recipients = ["xxx-xxx-xxxx"]
self.msg.messageComposeDelegate = self
self.present(msg, animated: false, completion: nil)
}
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
switch result.rawValue {
case MessageComposeResult.cancelled.rawValue:
dismiss(animated: true, completion: nil)
case MessageComposeResult.failed.rawValue:
dismiss(animated: true, completion: nil)
case MessageComposeResult.sent.rawValue:
dismiss(animated: true, completion: nil)
default:
break;
}
}
}
Try this code
import Foundation
import MessageUI
let textMessageRecipients = ["1-800-867-5309"] // for pre-populating the recipients list (optional, depending on your needs)
class MessageComposer: NSObject, MFMessageComposeViewControllerDelegate {
// A wrapper function to indicate whether or not a text message can be sent from the user's device
func canSendText() -> Bool {
return MFMessageComposeViewController.canSendText()
}
// Configures and returns a MFMessageComposeViewController instance
func configuredMessageComposeViewController() -> MFMessageComposeViewController {
let messageComposeVC = MFMessageComposeViewController()
messageComposeVC.messageComposeDelegate = self // Make sure to set this property to self, so that the controller can be dismissed!
messageComposeVC.recipients = textMessageRecipients
messageComposeVC.body = "Hey friend - Just sending a text message in-app using Swift!"
return messageComposeVC
}
// MFMessageComposeViewControllerDelegate callback - dismisses the view controller when the user is finished with it
func messageComposeViewController(controller: MFMessageComposeViewController!, didFinishWithResult result: MessageComposeResult) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
}
Note, latest syntax 2017 ..
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
controller.dismiss(animated: true, completion: nil)
}
In Your viewController ..
import UIKit
class ViewController: UIViewController {
// Create a MessageComposer
let messageComposer = MessageComposer()
#IBAction func sendTextMessageButtonTapped(sender: UIButton) {
// Make sure the device can send text messages
if (messageComposer.canSendText()) {
// Obtain a configured MFMessageComposeViewController
let messageComposeVC = messageComposer.configuredMessageComposeViewController()
// Present the configured MFMessageComposeViewController instance
// Note that the dismissal of the VC will be handled by the messageComposer instance,
// since it implements the appropriate delegate call-back
presentViewController(messageComposeVC, animated: true, completion: nil)
} else {
// Let the user know if his/her device isn't able to send text messages
let errorAlert = UIAlertView(title: "Cannot Send Text Message", message: "Your device is not able to send text messages.", delegate: self, cancelButtonTitle: "OK")
errorAlert.show()
}
}
}