Adding Suport Mail

While including a flow for contacting support often comes as a last minute after-thought,
having a great complaining experience can be instrumental in further improving the app.
This is by no means a complex task, though there are a few gotchas along the way.

Gathering Context

Feedback is often caused by a regression, which has been introduced in a certain release version, or only occurs in a specific environment.
Therefore, it's useful to include this sort of data in the initial support request. This avoids unnecessary back and forth. Here's an example of gathering some commonly required context.

var app: String {"CFBundleDisplayName") + " " +"CFBundleShortVersionString")

var os: String {
#if os(iOS)
	let platform = "iOS "
#elseif os(macOS)
	let platform = "MacOS "
	return platform + ProcessInfo.processInfo.operatingSystemVersionString

I'm using following extension to make fetching data from the app's bundle more convenient.

extension Bundle {
	func info(_ key: String) -> String {
		infoDictionary.flatMap { $0[key] as? String }
		?? "Missing " + key

The mailto: URI scheme supports specifying subject and body using query parameters,
which are then parsed by the user's default mail client.

var mailTo: URL {
	URL(string: "mailto:\(supportEmail)")!
			queryItems: [
				URLQueryItem(name: "subject", value: "Support: \(app)"),
				URLQueryItem(name: "body", value: "\n\n\nOS: \(os)\nApp: \(app)"),

User Interface

When all is done, SwiftUI offers various ways of opening the constructed link:

struct ContactSupportView: View {
	@Environment(\.openURL) private var openURL

	var body: some View {
		Button("Contact Support") { openURL(mailTo) }
		stringLiteral: "Contact us [\(supportEmail)](\(mailTo))!"
Link("Contact Support", destination: mailTo)


Now users can create a simple mail template with a single tap! As a bonus, consistent titles allow for some automation when handling support. This is especially true in cases where multiple apps are served from a single support mail address.