Creating Email Functionality in SwiftUI Apps
Written on
Chapter 1: Introduction to Email Integration
In this guide, we will explore how to incorporate email functionality into a SwiftUI application. You might wonder how challenging this task could be. Fortunately, utilizing the MVVM pattern simplifies the process without adding complexity.
This article was crafted using Xcode 12.4 and Swift 5.7.2.
Section 1.1: Setting Up the Protocol
To facilitate sending emails, we need to define a protocol for the UIApplication. This allows us to inject it into our view model seamlessly.
protocol OpenURLProtocol {
func open(_ url: URL)
}
extension UIApplication: OpenURLProtocol {
func open(_ url: URL) {
open(url, options: [:], completionHandler: nil)}
}
This protocol can be injected into the view model through its initializer.
Subsection 1.1.1: ViewModel Implementation
final class ViewModel: ObservableObject {
let openURL: OpenURLProtocol
init(openURL: OpenURLProtocol = UIApplication.shared) {
self.openURL = openURL}
func email() {
guard let url = URL(string: "mailto:[email protected]") else { return }
openURL.open(url)
}
func emailWithSubject() {
let subject = "Feedback"
let encodedSubject = subject.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
guard let url = URL(string: "mailto:[email protected]?subject=(encodedSubject)") else { return }
openURL.open(url)
}
func emailWithSubjectAndBody() {
let subject = "Feedback"
let body = "I wanted to share some feedback about...'the issue' ok"
let encodedSubject = subject.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let encodedBody = body.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
if let url = URL(string: "mailto:[email protected]?subject=(encodedSubject)&body=(encodedBody)") {
openURL.open(url)}
}
}
Section 1.2: Building the ContentView
Now we will create our ContentView, where users can trigger the email functionality.
struct ContentView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Button("Click me to email") {
viewModel.email()}
Button("Click me to email with subject populated") {
viewModel.emailWithSubject()}
Button("Click me to email with subject and body populated") {
viewModel.emailWithSubjectAndBody()}
}
.padding()
}
}
Chapter 2: Testing the Functionality
To ensure our implementation works correctly, we can create a series of tests.
import XCTest
@testable import OpenCallSwiftUI
final class OpenEmailSwiftUITests: XCTestCase {
func testEmail() throws {
let expectedUrl = URL(string: "mailto:[email protected]")
let mockApplicationURLOpener = MockApplicationURLOpener()
let vm = ViewModel(openURL: mockApplicationURLOpener)
vm.email()
XCTAssertEqual(mockApplicationURLOpener.urlOpened, expectedUrl)
}
func testEmailWithSubject() throws {
let expectedUrl = URL(string: "mailto:[email protected]?subject=Feedback")
let mockApplicationURLOpener = MockApplicationURLOpener()
let vm = ViewModel(openURL: mockApplicationURLOpener)
vm.emailWithSubject()
XCTAssertEqual(mockApplicationURLOpener.urlOpened, expectedUrl)
}
func testEmailWithSubjectAndBody() throws {
let expectedUrl = URL(string: "mailto:[email protected]?subject=Feedback&body=I%20wanted%20to%20share%20some%20feedback%20about...'the%20issue'%20ok")
let mockApplicationURLOpener = MockApplicationURLOpener()
let vm = ViewModel(openURL: mockApplicationURLOpener)
vm.emailWithSubjectAndBody()
XCTAssertEqual(mockApplicationURLOpener.urlOpened, expectedUrl)
}
}
final class MockApplicationURLOpener: OpenURLProtocol {
var urlOpened: URL?
func open(_ url: URL) {
urlOpened = url}
}
Chapter 3: Conclusion
This guide demonstrates a straightforward method to create email functionality within a SwiftUI application. If you have any questions or feedback, feel free to reach out!
Here’s a video tutorial on adding email support requests to a SwiftUI project.
Check out this video on sending emails from SwiftUI for more insights!