I would like to make the "Leave a Suggestion" static cell open the mail and allow me to compose a message with a set subject. How would I accomplish this?
EDIT:
import UIKit
import MessageUI
class AccountViewController: UITableViewController, MFMailComposeViewControllerDelegate {
#IBOutlet var Logout: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
#IBAction func emailButtonAction(_ sender: UIButton) {
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients(["example#gmail.com"])
mail.setSubject("Example Subject")
mail.setMessageBody("<p>Test</p>", isHTML: true)
present(mail, animated: true)
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true)
}
}
UIButton does not work with any of my cells
Related
I'm trying to implement sending email feature into my mini app.
Here's the code I'm using (took it from https://hackingwithswift.com):
import Foundation
import SwiftUI
import MessageUI
func sendEmail() {
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients(["you#yoursite.com"])
mail.setMessageBody("<p>You're so awesome!</p>", isHTML: true)
present(mail, animated: true)
} else {
// show failure alert
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true)
}
When running my code, I get these 2 errors:
Cannot find self in scope
Cannot find present in scope
How can I fix it?
You can use UIViewControllerRepresentable
MailComposeViewController
struct MailComposeViewController: UIViewControllerRepresentable {
var toRecipients: [String]
var mailBody: String
var didFinish: ()->()
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MailComposeViewController>) -> MFMailComposeViewController {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = context.coordinator
mail.setToRecipients(self.toRecipients)
mail.setMessageBody(self.mailBody, isHTML: true)
return mail
}
final class Coordinator: NSObject, MFMailComposeViewControllerDelegate {
var parent: MailComposeViewController
init(_ mailController: MailComposeViewController) {
self.parent = mailController
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
parent.didFinish()
controller.dismiss(animated: true)
}
}
func updateUIViewController(_ uiViewController: MFMailComposeViewController, context: UIViewControllerRepresentableContext<MailComposeViewController>) {
}
}
Usage:
struct MailView: View {
#State private var showingMail = false
var body: some View {
VStack {
Button("Open Mail") {
self.showingMail.toggle()
}
}
.sheet(isPresented: $showingMail) {
MailComposeViewController(toRecipients: ["test#gmail.com"], mailBody: "Here is mail body") {
// Did finish action
}
}
}
}
Possible another solution. You can create one singleton class and present MFMailComposeViewController on the root controller. You can modify function as per your requirement. Like this
class MailComposeViewController: UIViewController, MFMailComposeViewControllerDelegate {
static let shared = MailComposeViewController()
func sendEmail() {
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients(["you#yoursite.com"])
mail.setMessageBody("<p>You're so awesome!</p>", isHTML: true)
UIApplication.shared.windows.first?.rootViewController?.present(mail, animated: true)
} else {
// show failure alert
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true)
}
}
Usage:
Button(action: {
MailComposeViewController.shared.sendEmail()
}, label: {
Text("Send")
})
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'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()
}
}
}
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{
I am trying to send a mail from the collection view cell controller, but I get error. Here is full code:
import Foundation
import UIKit
import MessageUI
import Parse
import Bolts
class CollectionViewCell: UICollectionViewCell, MFMailComposeViewControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var imageText: UILabel!
#IBOutlet weak var uploadedTimeLabel: UILabel!
#IBOutlet weak var currentUserLabel: UILabel!
#IBOutlet weak var flagContentButton: UIButton!
var deviceID = [String]()
var parseObject:PFObject?
#IBAction func buttonClick(sender: AnyObject) {
println(deviceID)
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self // Extremely important to set the --mailComposeDelegate-- property, NOT the --delegate-- property
mailComposerVC.setToRecipients(["test#email.com"])
mailComposerVC.setSubject("Test subject")
mailComposerVC.setMessageBody("Test mail!", isHTML: false)
return mailComposerVC
}
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail. Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
sendMailErrorAlert.show()
}
// MARK: MFMailComposeViewControllerDelegate
func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
}
Error line:
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
Error code:
'CollectionViewCell' does not have a member named
'presentViewController'
Any suggestions what to do here?
You could use completion blocks or a delegate to notify the view controller, like below. You would set either delegate or notifyViewController on the cell in your cellForItemAtIndexPath. This way, you can tell each cell which controller you want to handle presenting the mail controller and the controller can decide how to do it.
protocol CollectionViewCellDelegate {
func notifyViewController(mailViewController: MFMailComposeViewController)
}
class CollectionViewCell: ... {
//...
var delegate: CollectionViewCellDelegate?
// you could use this completion block property in place of a delegate
var notifyViewController: ((MFMailComposeViewController) -> Void)?
//...
#IBAction func buttonClick(sender: AnyObject) {
println(deviceID)
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
delegate?.notifyViewController(mailComposeViewController)
// OR
notifyViewController?(mailComposeViewController)
} else {
self.showSendMailErrorAlert()
}
}
//...
}