Actual Links Email Linking: iOS Developer Guide

This guide covers everything you need to integrate email linking into your iOS app: how it works, authentication, retrieval, configuration, and references.

How It Works

  1. Authenticate — The user connects their email account through your app using IMAP. Credentials are stored on-device only and are never sent to or stored on Actual servers.
  2. Extract — The SDK searches the user’s inbox for receipt emails from supported merchants and returns structured purchase data.
  3. Enrich (optional) — If Product Intelligence is enabled, extracted line items are matched against the product catalog for UPC, brand, and category.

Supported Email Providers

ProviderAuthenticationNotes
GmailIMAP with App PasswordSDK automates App Password creation, or user can enable Less Secure Apps
YahooIMAP with App PasswordSDK automates App Password creation
AOLIMAP with App PasswordSDK automates App Password creation

The SDK supports linking multiple IMAP accounts simultaneously.

Choose Your Integration Approach

ApproachHow it worksBest for
On-Device (Local)SDK searches the inbox directly from the user’s device. Results returned immediately in callback.Real-time results while the user is in the app
On-Device Auth + Server Processing(Recommended)User authenticates on-device. Inbox search happens asynchronously on Actual’s server. Results posted to your webhook.Background processing without requiring the app to stay open
Server-OnlyNo SDK. Send email data (EML format) directly to the remote scrape API.Systems that already collect email data externally
Email ForwardingUsers forward receipts to a dedicated inbox. Actual processes every two minutes.Passive collection, minimal integration effort

Installation

Email linking uses the BlinkEReceipt extension SDK (separate from the base SDK).

CocoaPods:

pod 'BlinkEReceipt'

Swift Package Manager:

https://github.com/BlinkReceipt/blinkereceipt-ios

Prerequisites: Xcode 12+, iOS 11.0+ deployment target.

→ BlinkEReceipt iOS (GitHub)

License Keys

You need two keys: a license key and a Product Intelligence key. Set both in your AppDelegate:

import BlinkReceipt
import BlinkEReceipt

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    BRScanManager.shared().licenseKey = "YOUR-LICENSE-KEY"
    BRScanManager.shared().prodIntelKey = "YOUR-PROD-INTEL-KEY"
    return true
}

IMAP Authentication (Gmail, Yahoo, AOL)

IMAP authentication requires the user’s email address and an App Password (not their regular account password). The SDK automates App Password creation for all supported providers.

Step 1: Collect Credentials

Build your own UI to collect the user’s email and regular account password, then create an IMAP account object:

BRIMAPAccount *imapAcct = [[BRIMAPAccount alloc] initWithProvider:BREReceiptProviderYahoo
                                                            email:userEmail
                                                         password:userPassword];

Step 2: Run IMAP Setup

The SDK logs into the user’s account and attempts to create an App Password automatically. For Gmail, it checks whether Less Secure Apps is already enabled:

[[BREReceiptManager shared] setupIMAPForAccount:imapAcct
                                 viewController:self
                                 withCompletion:^(BRSetupIMAPResult result) {

    if (result == BRSetupIMAPResultCreatedAppPassword) {
        NSLog(@"Successfully created app password.");
    } else if (result == BRSetupIMAPResultEnabledLSA) {
        NSLog(@"Successfully enabled Gmail Less Secure Apps.");
    }
}];

Step 3: Verify the Connection

Once setup succeeds, verify the IMAP connection:

[[BREReceiptManager shared] verifyImapAccount:imapAcct
                               withCompletion:^(BOOL success, NSError *error) {

    if (success) {
        // Credentials verified
    } else {
        // Failed to verify credentials
    }
}];

Already Have an App Password?

If users have already generated an App Password, skip the automated setup and link directly:

[[BREReceiptManager shared] linkIMAPAccountWithoutSetup:imapAcct
                                         withCompletion:^(BRSetupIMAPResult result) {
    // Handle result
}];

Retrieving Email Receipts

Local Retrieval

Use when the user is actively in the app and you want immediate results. The SDK connects directly to the email provider, searches the inbox, and returns results:

[[BREReceiptManager shared] getEReceiptsWithCompletion:^(NSArray<BRScanResults *> *receipts,
                                                          BREmailAccount *account,
                                                          NSError *error) {
    if (error == nil) {
        NSLog(@"Found %lu new e-receipt orders", (unsigned long)receipts.count);
    } else {
        NSLog(@"Error retrieving e-receipts");
    }
}];

Limitation: If the user exits the app during processing, no results are received. Use remote retrieval for background processing.

Remote Retrieval (Recommended)

Authentication stays on-device, but the inbox search happens server-side. Results are posted to your configured webhook endpoint:

[[BREReceiptManager shared] startRemoteEReceiptScrapeForAccount:account
                                                 withCompletion:^(NSString *jobId, NSError *error) {
    if (error == nil) {
        // Job successfully queued — results will be posted to your webhook
    } else {
        // Job failed to queue
    }
}];

Server-side configuration required:

SettingDescription
Webhook endpoint URLWhere Actual posts results
Retailer email addressesWhich merchants to look for
Cutoff datesPer-retailer or global
Country code (optional)Improves extraction if receipts are from a specific country

 eReceipts Configuration API (SwaggerHub) → Webhook Documentation

Search Window Configuration

Control how far back to search in the user’s email:

PropertyWhat it doesDefault
BREReceiptManager.dayCutoffNumber of days back to search14 days
BREReceiptManager.dateCutoffSpecific earliest date to search fromNone
BREReceiptManager.searchUntilDateLatest date to search until (if not present day)None
BREReceiptManager.remoteScrapeUserDateCutoffOverride cutoff per user for remote scrapingNone
BREReceiptManager.remoteScrapeClientEndpointOverride the results endpoint for debuggingNone

Signing Out

To disconnect a linked email account:

[[BREReceiptManager shared] signOutFromAccount:account
                                withCompletion:^(NSError *error) {
    // Account disconnected
}];

For OAuth providers, this signs out and invalidates the access token. For IMAP providers, this removes stored credentials.

Email Receipt Data

Email receipts return the same core fields as paper receipts (merchant, date, total, line items) plus additional fields:

FieldDescription
ereceiptOrderNumOrder number from the email receipt
ereceiptRawHTMLRaw HTML content of the receipt email
shippingStatusShipping status per line item
ereceiptComponentEmailsComponent emails for aggregated orders

For the full list of returned fields, see the Data Reference →.

Supported Merchant Emails

The list of merchant email senders that Actual processes is publicly available and updated regularly.

 Supported Merchant Emails

Emails from senders not on this list are not processed or stored.


Error Handling

Error typeReference
IMAP errors (auth failures, App Password issues, connection timeouts)iOS IMAP Error Codes
Remote scraping errors (job failures, processing issues)Remote Error Codes (SwaggerHub)

Testing Recommendations

  • Test each supported provider (Gmail, Yahoo, AOL) end to end
  • Test with accounts that have varying volumes of receipt emails
  • Test the remote scraping flow including webhook delivery
  • Verify cutoff date behavior
  • Test account unlinking and re-authentication
  • Test aggregation with orders that generate multiple emails

Implementation Timeline

ScopeEstimated Dev Time
Single provider~1 week + QA
All providers + remote scraping~2 weeks + QA
Server-side webhook setupAdditional ~1 week

Key Classes & References

ClassWhat it does
BREReceiptManagerMain manager for email linking, retrieval, and configuration
BRIMAPAccountRepresents an IMAP email account (credentials + provider)
BREmailAccountBase class for linked email accounts
BREReceiptIMAPErrorIMAP-specific error codes
BREReceiptRemoteErrorRemote scraping error codes
BREReceiptProviderEmail provider enum values
BRSetupIMAPResultIMAP setup result codes

Related

Let’s Turn Proof Into Action 

Your next move should be backed by proof, and we’re here to help you leverage real data for real results. Start turning verified insights into measurable impact today.