Skip to content

Swift SDK Reference

Complete API reference for the MailJawn Swift SDK. For a quick-start walkthrough, see Install the Swift SDK.

Requirements

Requirement Minimum
iOS 15.0+
macOS 12.0+
Swift 6
Xcode with Swift Package Manager

Installation

Add the SDK using Swift Package Manager:

  1. In Xcode, go to File > Add Package Dependencies...
  2. Enter the package URL:

    https://github.com/AcmeSoftware/mailjawn-swift-sdk
    
  3. Select your version rule and add the package to your target.

Then import it:

import MailjawnSwift

Configuration

configure(apiKey:projectId:baseURL:)

Initialize the SDK. Call this once, as early as possible in your app's lifecycle.

try await Mailjawn.configure(
    apiKey: "mj_your_api_key_here",
    projectId: UUID(uuidString: "your-project-uuid")!
)
Parameter Type Required Description
apiKey String Yes Your API key. Must start with mj_.
projectId UUID Yes Your app's project UUID from the MailJawn dashboard.
baseURL URL? No Override the default API URL. Defaults to https://api.mailjawn.com/api/v1.

Behavior:

  • Validates the API key starts with mj_ — throws MailjawnError.invalidAPIKey if not
  • Stores the API key securely in the device Keychain
  • Must be called before any other SDK method

Warning

Calling any SDK method before configure() throws MailjawnError.notConfigured.

Example — SwiftUI App init:

import MailjawnSwift

@main
struct MyApp: App {
    init() {
        Task {
            try await Mailjawn.configure(
                apiKey: "mj_your_api_key_here",
                projectId: UUID(uuidString: "your-project-uuid")!
            )
        }
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

User Identification

identify(userId:)

Associate the current device with a user ID. This is a local operation — no network call is made.

await Mailjawn.identify(userId: "user-123")
Parameter Type Required Description
userId String Yes Your app's user identifier.

Call this when a user signs in. The user ID is attached to subsequent API calls.

setEmail(_:) and setEmail(_:name:)

Register or update a subscriber in MailJawn. This is the primary method for getting users into your subscriber list.

// Email only
let result = try await Mailjawn.setEmail("user@example.com")

// Email with name
let result = try await Mailjawn.setEmail("user@example.com", name: "Jane Doe")
Parameter Type Required Description
email String Yes Subscriber's email address.
name String No Subscriber's display name.

Returns: IdentifyResult

public struct IdentifyResult: Sendable {
    public let subscriberId: UUID    // The subscriber's unique ID
    public let isNewSubscriber: Bool // true if just created, false if updated
}

Behavior:

  • Makes a network call to POST /subscribers/identify/
  • Upserts the subscriber — creates if new, updates if existing
  • Automatically attaches device metadata to the request
  • Validates email client-side (must contain @ with non-empty local and domain parts, domain must contain .)
  • Throws MailjawnError.invalidEmail if validation fails
  • Triggers welcome automations for new subscribers

setUserProperties(_:)

Attach custom fields to the current subscriber. These fields appear in the subscriber profile and can be used in segments and template variables.

try await Mailjawn.setUserProperties([
    "plan": "premium",
    "signup_source": "referral",
    "trial_days_left": 14,
    "is_beta": true
])
Parameter Type Required Description
properties [String: Any] Yes Key-value pairs to merge into the subscriber's custom fields.

Accepted value types:

Swift Type JSON Type Example
String string "premium"
Int number 42
Double number 3.14
Bool boolean true

Properties are merged with existing custom fields — keys you don't include are left unchanged.

reset()

Clear all local SDK state. Call this when a user logs out.

await Mailjawn.reset()

Behavior:

  • Clears the locally stored user ID, email, and custom properties
  • No network call is made
  • The subscriber record in MailJawn is unaffected
  • You'll need to call identify() and setEmail() again for the next user

Auto-Captured Fields

When you call setEmail(), the SDK automatically collects and sends device metadata alongside the subscriber data. You don't need to set these manually.

Field Source Example
deviceType UIDevice / Host "iPhone", "iPad", "Mac"
osVersion ProcessInfo / UIDevice "iOS 17.2", "macOS 14.1"
appVersion Bundle.main "2.3.1" (from CFBundleShortVersionString)
locale Locale.current "en_US", "it_IT"
timezone TimeZone.current "America/New_York" (IANA identifier)
sdkVersion SDK constant "1.0.0"

These fields appear on the subscriber profile in the dashboard and can be used for segments (e.g., "all iPhone users on iOS 17+").

Error Handling

All throwing SDK methods can throw MailjawnError:

public enum MailjawnError: Error, Sendable {
    case notConfigured
    case invalidAPIKey
    case invalidEmail
    case networkError(underlying: any Error)
    case serverError(statusCode: Int, message: String)
    case decodingError(underlying: any Error)
    case encodingError(underlying: any Error)
    case keychainError(status: OSStatus)
}
Error When It Happens
notConfigured You called an SDK method before configure().
invalidAPIKey The API key doesn't start with mj_.
invalidEmail The email failed client-side validation.
networkError The device couldn't reach the server (no internet, DNS failure, timeout).
serverError The server returned a 4xx or 5xx response. Check statusCode and message.
decodingError The server response couldn't be parsed.
encodingError The request body couldn't be serialized (e.g., invalid custom field types).
keychainError The API key couldn't be stored in or read from the Keychain.

Example — handling errors:

do {
    let result = try await Mailjawn.setEmail("user@example.com")
    print("Subscriber \(result.subscriberId), new: \(result.isNewSubscriber)")
} catch let error as MailjawnError {
    switch error {
    case .notConfigured:
        print("SDK not configured — call Mailjawn.configure() first")
    case .invalidEmail:
        print("Invalid email address")
    case .networkError(let underlying):
        print("Network issue: \(underlying.localizedDescription)")
    case .serverError(let code, let message):
        print("Server error \(code): \(message)")
    default:
        print("Error: \(error.localizedDescription)")
    }
}

Thread Safety

The SDK is fully thread-safe. All public methods are async and use a Swift actor internally to manage state. All public types conform to Sendable. You can call SDK methods from any thread or task without synchronization.

Keychain Storage

The SDK stores your API key in the device Keychain with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly protection. This means:

  • The key is encrypted at rest
  • It's available after the first device unlock (no need to unlock before background operations)
  • It doesn't sync to other devices or iCloud Keychain
  • It persists across app updates but is removed on app uninstall

Planned Features

Note

The following methods are specified in the SDK design but not yet shipped. They will be added in a future release.

  • track(event:properties:) — Record custom events for automation triggers
  • flush() — Force-send any queued events immediately

See also: Quick Start > Install the Swift SDK | REST API for platform-agnostic access