Danny의 iOS 컨닝페이퍼
article thumbnail

[Swift/ TIL #36] 2023 / 07 / 11

이전에 이미 메일 보내는 기능을 구현을 해봤었는데,

오랜만에 다시 구현하려니 헷갈려서 간단히 정리한 뒤, 다시 사용하려고 이렇게 정리합니다.

 

사용방법은 공식문서 에 자세히 설명이 돼있어요.

 

 

시작

이렇게 버튼을 만들어줬고 버튼을 클릭하면 mail을 보내는 기능을 만들어 보려합니다.

class ViewController: UIViewController {
    
    lazy var button: UIButton = {
        let button = UIButton(configuration: .filled())
        button.frame = CGRect(x: 150, y: 400, width: 100, height: 50)
        button.setTitle("문의 사항", for: .normal)
        button.addTarget(self, action: #selector(buttonHandler), for: .touchUpInside)
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(button)
    }
    
    @objc func buttonHandler(_ sender: UIButton) {
    
    }
}

 

가장 처음으로 Mail 기능을 사용하기 위해 프레임워크를 추가해 줍니다.

import MessageUI

 

다음으로 사용자 디바이스에서 email 기능이 활성화돼 있는지 여부를 확인해줘야 합니다.

만약, email이 비활성화돼 있을 경우는 사용자에게 따로 알려줘야겠죠!

if MFMailComposeViewController.canSendMail() {
    // 메일 작성 화면 설정
} else {
    // 만약, 디바이스에 email 기능이 비활성화 일 때, 사용자에게 알림
}

 

들어가기 전, 메일 작성 화면이 어떻게 구성돼 있나, 그림과 같이 살펴봅시다.

 

메일 작성 화면의 구성

Recipients: 받는 사람의 메일 주소

Subject: 제목

MessageBody: 본문 내용

 

위의 작성 화면 규격대로 만들어봅시다.

@objc func buttonHandler(_ sender: UIButton) {
    if MFMailComposeViewController.canSendMail() {
        let composeVC = MFMailComposeViewController()
        composeVC.mailComposeDelegate = self
        
        let bodyString = """
                         이곳에 내용을 작성해 주세요.
                         
                         
                         ================================
                         Device Model : \(UIDevice.current.modelName)
                         Device OS : \(UIDevice.current.systemVersion)
                         App Version : \(currentAppVersion)
                         ================================
                         """
        
        // 받는 사람 이메일, 제목, 본문
        composeVC.setToRecipients(["scarlet040@gmail.com"])
        composeVC.setSubject("문의 사항")
        composeVC.setMessageBody(bodyString, isHTML: false)
        
        self.present(composeVC, animated: true)
    } else {
        // 만약, 디바이스에 email 기능이 비활성화 일 때, 사용자에게 알림
        let alertController = UIAlertController(title: "메일 계정 활성화 필요",
                                                message: "Mail 앱에서 사용자의 Email을 계정을 설정해 주세요.",
                                                preferredStyle: .alert)
        let alertAction = UIAlertAction(title: "확인", style: .default) { _ in
            guard let mailSettingsURL = URL(string: UIApplication.openSettingsURLString + "&&path=MAIL") else { return }
            
            if UIApplication.shared.canOpenURL(mailSettingsURL) {
                UIApplication.shared.open(mailSettingsURL, options: [:], completionHandler: nil)
            }
        }
        alertController.addAction(alertAction)
        
        self.present(alertController, animated: true)
    }
}

 

델리게이트 메서드를 통해 각 분기마다 추가 설정도 가능합니다.

extension ViewController: MFMailComposeViewControllerDelegate {
    // 메일 작성이 끝났을 때, 호출되는 메서드
    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        switch result {
        case .sent:
            print("메일 보내기 성공")
        case .cancelled:
            print("메일 보내기 취소")
        case .saved:
            print("메일 임시 저장")
        case .failed:
            print("메일 발송 실패")
        @unknown default: break
        }
        
        // 자동으로 dismiss가 되지 않으므로, 작업 완료 시 dismiss를 해줘야 함
        self.dismiss(animated: true)
    }
}

 

 

전체 코드

import UIKit
import MessageUI

class ViewController: UIViewController {
    
    lazy var button: UIButton = {
        let button = UIButton(configuration: .filled())
        button.frame = CGRect(x: 150, y: 400, width: 100, height: 50)
        button.setTitle("문의 사항", for: .normal)
        button.addTarget(self, action: #selector(buttonHandler), for: .touchUpInside)
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(button)
    }
    
    @objc func buttonHandler(_ sender: UIButton) {
        if MFMailComposeViewController.canSendMail() {
            let composeVC = MFMailComposeViewController()
            composeVC.mailComposeDelegate = self
            
            let bodyString = """
                             이곳에 내용을 작성해 주세요.
                             
                             
                             ================================
                             Device Model : \(UIDevice.current.modelName)
                             Device OS : \(UIDevice.current.systemVersion)
                             App Version : \(currentAppVersion)
                             ================================
                             """
            
            composeVC.setToRecipients(["scarlet040@gmail.com"])
            composeVC.setSubject("문의 사항")
            composeVC.setMessageBody(bodyString, isHTML: false)
            
            self.present(composeVC, animated: true)
        } else {
            // 만약, 디바이스에 email 기능이 비활성화 일 때, 사용자에게 알림
            let alertController = UIAlertController(title: "메일 계정 활성화 필요",
                                                    message: "Mail 앱에서 사용자의 Email을 계정을 설정해 주세요.",
                                                    preferredStyle: .alert)
            let alertAction = UIAlertAction(title: "확인", style: .default) { _ in
                guard let mailSettingsURL = URL(string: UIApplication.openSettingsURLString + "&&path=MAIL") else { return }
                
                if UIApplication.shared.canOpenURL(mailSettingsURL) {
                    UIApplication.shared.open(mailSettingsURL, options: [:], completionHandler: nil)
                }
            }
            alertController.addAction(alertAction)
            
            self.present(alertController, animated: true)
        }
    }
}

extension ViewController: MFMailComposeViewControllerDelegate {
    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        switch result {
        case .sent:
            print("메일 보내기 성공")
        case .cancelled:
            print("메일 보내기 취소")
        case .saved:
            print("메일 임시 저장")
        case .failed:
            print("메일 발송 실패")
        @unknown default: break
        }
        
        self.dismiss(animated: true)
    }
}

// 현재 앱 버전 가져오기
fileprivate var currentAppVersion: String {
    guard let dictionary = Bundle.main.infoDictionary,
          let version = dictionary["CFBundleShortVersionString"] as? String else { return "" }
    return version
}
// 디바이스 모델 찾기
extension UIDevice {

    var modelName: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        
        switch identifier {
        case "i386", "x86_64": return "Simulator"
        case "iPhone1,1": return "iPhone"
        case "iPhone1,2": return "iPhone 3G"
        case "iPhone2,1": return "iPhone 3GS"
        case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4"
        case "iPhone4,1": return "iPhone 4S"
        case "iPhone5,1", "iPhone5,2": return "iPhone 5"
        case "iPhone5,3", "iPhone5,4": return "iPhone 5C"
        case "iPhone6,1", "iPhone6,2": return "iPhone 5S"
        case "iPhone7,1": return "iPhone 6 Plus"
        case "iPhone7,2": return "iPhone 6"
        case "iPhone8,1": return "iPhone 6s"
        case "iPhone8,2": return "iPhone 6s Plus"
        case "iPhone8,4": return "iPhone SE"
        case "iPhone9,1", "iPhone9,3": return "iPhone 7"
        case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus"
        case "iPhone10,1", "iPhone10,4": return "iPhone 8"
        case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus"
        case "iPhone10,3", "iPhone10,6": return "iPhone X"
        case "iPhone11,2": return "iPhone XS"
        case "iPhone11,4", "iPhone11,6": return "iPhone XS Max"
        case "iPhone11,8": return "iPhone XR"
        case "iPhone12,1": return "iPhone 11"
        case "iPhone12,3": return "iPhone 11 Pro"
        case "iPhone12,5": return "iPhone 11 Pro Max"
        case "iPhone12,8": return "iPhone SE (2nd generation)"
        case "iPhone13,1": return "iPhone 12 mini"
        case "iPhone13,2": return "iPhone 12"
        case "iPhone13,3": return "iPhone 12 Pro"
        case "iPhone13,4": return "iPhone 12 Pro Max"
        default: return identifier
        }
    }
}

 

 

참고, HTML으로 본문 생성

@objc func buttonHandler(_ sender: UIButton) {
    if MFMailComposeViewController.canSendMail() {
        let composeVC = MFMailComposeViewController()
        composeVC.mailComposeDelegate = self
        
        let bodyString = """
                         <html>
                         <body>
                            <h1>내용을 작성해 주세요.</h1><br>
                         
                            <p>================================
                            Device Model : \(UIDevice.current.modelName)<br>
                            Device OS : \(UIDevice.current.systemVersion)<br>
                            App Version : \(currentAppVersion)<br>
                            ===============================</p>
                         </body>
                         </html>
                         """
        
        composeVC.setToRecipients(["scarlet040@gmail.com"])
        composeVC.setSubject("문의 사항")
        // 👉 본문 내용을 HTML로 작성 후, isHTML을 true로 변경
        composeVC.setMessageBody(bodyString, isHTML: true)
        
        self.present(composeVC, animated: true)
    }
}

 

 

반응형
profile

Danny의 iOS 컨닝페이퍼

@Danny's iOS

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!