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
- 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.
- Extract — The SDK searches the user’s inbox for receipt emails from supported merchants and returns structured purchase data.
- Enrich (optional) — If Product Intelligence is enabled, extracted line items are matched against the product catalog for UPC, brand, and category.
Supported Email Providers
| Provider | Authentication | Notes |
|---|---|---|
| Gmail | IMAP with App Password | SDK automates App Password creation, or user can enable Less Secure Apps |
| Yahoo | IMAP with App Password | SDK automates App Password creation |
| AOL | IMAP with App Password | SDK automates App Password creation |
The SDK supports linking multiple IMAP accounts simultaneously.
Choose Your Integration Approach
| Approach | How it works | Best 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-Only | No SDK. Send email data (EML format) directly to the remote scrape API. | Systems that already collect email data externally |
| Email Forwarding | Users 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-iosPrerequisites: Xcode 12+, iOS 11.0+ deployment target.
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:
| Setting | Description |
|---|---|
| Webhook endpoint URL | Where Actual posts results |
| Retailer email addresses | Which merchants to look for |
| Cutoff dates | Per-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:
| Property | What it does | Default |
|---|---|---|
BREReceiptManager.dayCutoff | Number of days back to search | 14 days |
BREReceiptManager.dateCutoff | Specific earliest date to search from | None |
BREReceiptManager.searchUntilDate | Latest date to search until (if not present day) | None |
BREReceiptManager.remoteScrapeUserDateCutoff | Override cutoff per user for remote scraping | None |
BREReceiptManager.remoteScrapeClientEndpoint | Override the results endpoint for debugging | None |
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:
| Field | Description |
|---|---|
ereceiptOrderNum | Order number from the email receipt |
ereceiptRawHTML | Raw HTML content of the receipt email |
shippingStatus | Shipping status per line item |
ereceiptComponentEmails | Component 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.
Emails from senders not on this list are not processed or stored.
Error Handling
| Error type | Reference |
|---|---|
| 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
| Scope | Estimated Dev Time |
|---|---|
| Single provider | ~1 week + QA |
| All providers + remote scraping | ~2 weeks + QA |
| Server-side webhook setup | Additional ~1 week |
Key Classes & References
| Class | What it does |
|---|---|
| BREReceiptManager | Main manager for email linking, retrieval, and configuration |
| BRIMAPAccount | Represents an IMAP email account (credentials + provider) |
| BREmailAccount | Base class for linked email accounts |
| BREReceiptIMAPError | IMAP-specific error codes |
| BREReceiptRemoteError | Remote scraping error codes |
| BREReceiptProvider | Email provider enum values |
| BRSetupIMAPResult | IMAP setup result codes |