Mobile apps
Mobile UI tests use Proxy Mail QA the same way web tests do: create a test address, type it into the app’s sign-up screen, then wait for the code or link from the email. The helpers on these pages are test code only. Nothing goes into the app you ship.
Each helper does the same things, in its own language:
- Create a test address with a password for the form, and a date of birth, country or environment when you ask.
- Wait for the code or link, including the link that opens the app, and skip a code already used.
- Check the email: count what arrived (exactly one, not two), check it (SPF, DKIM, DMARC, local or http links, where its link goes), or check nothing arrives.
- Sign in as a saved account, or borrow one no other test has while tests run in parallel.
- Report on the pull request: with the GitHub Action, each call joins the job’s run, named by its test.
| Your tests | Guide |
|---|---|
| Maestro (native iOS and Android, React Native, Flutter) | Maestro |
| XCUITest in Xcode (Swift) | iOS (XCUITest) |
| Espresso or UI Automator in Android Studio (Kotlin) | Android (Espresso) |
Flutter integration_test (Dart) |
Flutter |
| Detox or Appium (JavaScript) | Detox and Appium |
| A coding agent driving the iOS Simulator | iOS apps with a coding agent |
A coding agent testing an Android app in the emulator works the same way through the MCP server, with whatever tool it has to drive the emulator. We haven’t written a guide for that yet.
For what to check on each platform (cold-start links, App Links that open Chrome, exp:// links, Firebase email-link sign-in), see the mobile app guides.
Keep the API key out of the app
Section titled “Keep the API key out of the app”Every guide reads the API key from the test run: an environment variable, an instrumentation argument or a --dart-define. Store it in your CI’s secrets. Never add it to the app’s configuration or Info.plist, where anyone with the app could read it.
Opening a verify or magic link in the app
Section titled “Opening a verify or magic link in the app”The link in the email is usually an https link that opens the app: a Universal Link on iOS, an App Link on Android. Open it on the device, not in a desktop browser:
| Where | How |
|---|---|
| XCUITest | XCUIApplication().open(url) |
| Espresso | startActivity with an ACTION_VIEW intent (see the guide) |
| Maestro | - openLink: ${output.link} |
| Detox | device.openURL({ url }) |
| Appium | driver.execute('mobile: deepLink', { url, package }) (Android) or { url, bundleId } (iOS) |
| By hand, iOS simulator | xcrun simctl openurl booted '<link>' |
| By hand, Android emulator | adb shell "am start -W -a android.intent.action.VIEW -d '<link>'" |
Links that use the app’s own scheme, like myapp://verify?token=… or Expo’s exp://…/--/verify, are picked out too, and classified the same way: waiting for a link returns them. When an email has both a web link and an app link for the same thing, the web link comes first; ask for the app one with app=true (each helper has an app option). GET /v1/addresses/{address}/messages lists every link in each email. Proxy Mail QA never opens links, and the app and the Chrome extension only let you copy app links, with the simulator and emulator commands next to them in the inbox.
Codes split into boxes
Section titled “Codes split into boxes”Many apps show one box per digit of the code. Type the whole code into the first box: most such fields move to the next box as each digit is typed. If yours doesn’t, type one digit into each box. Before submitting, check every box has its digit: a partial code counts as a wrong attempt, and many apps lock the account after a few.
Check the email, not just the code
Section titled “Check the email, not just the code”After the code or link arrives, check the email too: checkEmail with the domain your app’s links open (its Universal Link or App Link domain) returns the checks it fails, and countEmails catches a second email sent by mistake. Each guide shows them in its language, and the REST API says what each check means.
Testing against a server on your computer
Section titled “Testing against a server on your computer”The iOS simulator reaches your computer at localhost. The Android emulator doesn’t: it reaches your computer at 10.0.2.2. If the app sends verification links to localhost, they won’t open on an emulator; see Testing links that point at localhost.
The email checks fail links to localhost or a private address, since a real user couldn’t open them. While you test against your own computer, add its host (such as localhost:3000 or 10.0.2.2:3000) to the project’s dev environments in Project settings, or with POST /v1/project/dev-hosts, and links to it pass.
Text messages
Section titled “Text messages”Proxy Mail QA handles email only. Codes sent by SMS need a different tool.