Ahrara
Zero Retention. Simple. Free. Open Source.
Disposable email built for AI agents, QA and automation
Receive any email right in your browser or in an inbox on your computer. Use it from the terminal, your AI agent or your tests.
What, How & Why Ahrara
- What is Ahrara?
- Disposable email addresses with an inbox on your computer. Read messages in the terminal or browser, or automate with MCP, the local API and the SDKs.
- How does it work?
- Ahrara generates addresses locally. While it runs, the relay streams incoming emails over an encrypted connection to the inbox on your computer.
- Why use Ahrara?
- Test signups, verification codes and email templates with dedicated addresses. Keep test emails out of your personal inbox and let your agent handle repetitive checks.
How to use
Read your email in the browser or the terminal, hand it to your AI agent, or assert on it from your tests.
In the browser
Nothing to install: open the web app, create your address and read your emails right there. Your inbox stays in your browser.
Open the web appKeep the tab open to receive emails. What the browser version supports.
Inbox 2
CLI
Install Ahrara, then just run ahrara in your terminal. Your email address is created automatically.
Keep Ahrara running to receive emails.
ahrara- Status
- [+] Connected
- nIvUcbwtK1bCU7Ivf6iXR1WFXe9NL8Pl@ahrara.dev (+3 more)
- Web
- http://127.0.0.1:8787
- MCP
- http://127.0.0.1:8787/mcp
| Selected | Received (local) | From | Subject | Size |
|---|---|---|---|---|
| Selected email | GitHub <noreply@github.com> | Your verification code: 482916 | 1.0 KiB | |
| Linear <notifications@linear.app> | You're invited to the workspace | 1.4 KiB |
AI agents
The agent itself manages Ahrara.
Plugins, rules and MCP for 25 coding agents.
/plugin marketplace add Hitmasu/Ahrara
/plugin install ahrara@ahraraRun inside Claude Code, then reload plugins. The plugin needs Node.js 20+.
Using another agent? See agent installation for every supported host.
- Disposable address createdListening for emails through Ahrara MCP.
- Account created in your appSubmitted the signup form with the Ahrara address.
- Email verifiedUsed code
482916from the verification email to confirm the account. - Email templates validatedChecked subjects, plain text and HTML in the verification and welcome emails.
E2E passed. Account verified and email templates matched expectations.
SDKs
Give each test its own inbox. Use its address in a signup or password-reset flow, then wait for the email and extract a code or link. Each inbox connects directly to the relay, with no CLI running alongside.
Packages include the native library. Validated on Linux x64.
npm install @ahrara/sdkNode.js 20+.
See the SDK guide for filters, links, attachments and reusing an inbox.
import { Ahrara } from '@ahrara/sdk';
const inbox = await Ahrara.createInbox();
try {
// The application requests a verification email for inbox.address here.
const match = await inbox.waitForRegexMatch('[0-9]{6}', {
timeoutMs: 30_000,
filter: { subject: 'Verification' },
});
// The extracted code is available to the application.
const code = match.value;
} finally {
await inbox.close();
}
from ahrara import create_inbox
with create_inbox() as inbox:
# The application requests a verification email for inbox.address here.
match = inbox.wait_for_regex_match(
r"[0-9]{6}", timeout=30, filter={"subject": "Verification"},
)
code = match["value"]
# The extracted code is available to the application.
using System;
using System.IO;
using AhraraSdk;
await using var inbox = await Ahrara.CreateInboxAsync();
// The application requests a verification email for inbox.Address here.
var match = await inbox.WaitForRegexMatchAsync(
@"[0-9]{6}", timeout: TimeSpan.FromSeconds(30),
filter: new EmailFilter { Subject = "Verification" });
var code = match.Value;
// The extracted code is available to the application.
import dev.ahrara.Ahrara;
import dev.ahrara.EmailFilter;
import java.time.Duration;
class Example {
public static void main(String[] args) throws Exception {
try (var inbox = Ahrara.createInbox()) {
// The application requests a verification email for inbox.address() here.
var match = inbox.waitForRegexMatch(
"[0-9]{6}", Duration.ofSeconds(30),
EmailFilter.builder().subject("Verification").build());
var code = match.value();
// The extracted code is available to the application.
}
}
}
package main
import (
"context"
"time"
ahrara "github.com/Hitmasu/Ahrara/src/sdks/go"
)
func receive(ctx context.Context) error {
inbox, err := ahrara.CreateInbox(ctx, ahrara.Options{})
if err != nil { return err }
defer inbox.Close()
// The application requests a verification email for inbox.Address here.
wait, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
match, err := inbox.WaitForRegexMatch(wait, `[0-9]{6}`,
ahrara.RegexOptions{Filter: ahrara.Filter{Subject: "Verification"}})
if err != nil { return err }
_ = match.Value // The extracted code is available to the application.
return nil
}
func main() {
if err := receive(context.Background()); err != nil { panic(err) }
}
use ahrara_core::{Inbox, InboxOptions, WaitOptions};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let inbox = Inbox::create(InboxOptions::default()).await?;
let result = async {
// The application requests a verification email for inbox.address() here.
let options = WaitOptions {
timeout_ms: Some(30_000),
subject: Some("Verification".into()),
..Default::default()
};
let matched = inbox.wait_for_regex_match("[0-9]{6}", options).await?
.ok_or_else(|| anyhow::anyhow!("Email timed out"))?;
let _code = matched.value;
// The extracted code is available to the application.
Ok::<(), anyhow::Error>(())
}.await;
inbox.close().await;
result
}
import ahrara from 'k6/x/ahrara';
export default function () {
const inbox = ahrara.createInbox({});
try {
// The application requests a verification email for inbox.address here.
const match = inbox.waitForRegexMatch('[0-9]{6}', {
durationMs: 30_000,
filter: { subject: 'Verification' },
});
// The extracted code is available to the application.
const code = match.value;
} finally {
inbox.close();
}
}
Test frameworks
Create the inbox in your test setup, use its address in the flow under test and close it in teardown.
Use the SDK from the framework you already run.
npm install @ahrara/sdkOwn the inbox in a Node test fixture.
The same APIs work with xUnit, NUnit, MSTest, pytest and JUnit, and with Selenium through the Java SDK.
import { test, expect } from '@playwright/test';
import { Ahrara } from '@ahrara/sdk';
test.use({ baseURL: 'https://app.example.com' });
test('receives the email', async ({ page }) => {
const inbox = await Ahrara.createInbox();
try {
await page.goto('/signup');
await page.getByLabel('Email', { exact: true }).fill(inbox.address);
await page.getByRole('button', { name: 'Sign up', exact: true }).click();
const match = await inbox.waitForRegexMatch('[0-9]{6}', {
timeoutMs: 30_000,
filter: { subject: 'Verification' },
});
await page.getByLabel('Verification code').fill(match.value);
await page.getByRole('button', { name: 'Verify', exact: true }).click();
await expect(page.getByText('Verified', { exact: true })).toBeVisible();
} finally {
await inbox.close();
}
});
describe('Email flow', () => {
let address;
afterEach(() => {
if (address) {
const current = address;
address = undefined;
cy.task('closeInbox', current);
}
});
it('receives the email', () => {
cy.task('createInbox', {}).then(value => {
address = value;
cy.visit('/signup');
cy.get('[name="email"]').type(address);
cy.contains('button', 'Sign up').click();
cy.task('waitForRegexMatch', {
address, pattern: '[0-9]{6}', subject: 'Verification',
}, { timeout: 35_000 }).then(result => {
cy.get('[name="code"]').type(result.value);
cy.contains('button', 'Verify').click();
cy.contains('Verified').should('be.visible');
});
});
});
});
*** Settings ***
Library ahrara.robot.AhraraLibrary WITH NAME Ahrara
Library SeleniumLibrary
Test Teardown Run Keywords Ahrara.Close Inbox AND Close All Browsers
*** Test Cases ***
Receive Email
${address}= Ahrara.Create Inbox
Open Browser https://app.example.com/signup chrome
Input Text name:email ${address}
Click Button Sign up
${filter}= Create Dictionary subject=Verification
${match}= Ahrara.Wait For Regex Match [0-9]{6} timeout=30 filter=${filter}
Input Text name:code ${match}[value]
Click Button Verify
Wait Until Page Contains Verified
Zero Data Retention
The Ahrara server saves no emails or address records. Its stateless design keeps delivery simple, with no server inbox to maintain.
You own your email
Your addresses are generated locally and tied to your cryptographic Identity. Your private key stays on your computer and proves ownership when you connect.
- Incoming emailDelivered in real time
- Ahrara serverNo email retained
- Your computerYour local inbox
Your emails and addresses are saved only on your computer.
100% Free
All Ahrara features are free to use. No account needed. Open source.
Donations are welcome and entirely optional.
FAQ
Does Ahrara store my emails or addresses on its servers?
No. Messages pass through the server without being saved, and email addresses are not registered there. Your inbox and addresses are stored locally on your computer.
Can I send emails with Ahrara?
No. Ahrara only receives emails. It does not support sending messages or replying to them.
Is Ahrara an open email relay?
No. Senders can deliver email without logging in, but Ahrara never relays it to external mail servers. Messages go only to the authenticated Ahrara client for the receiving address.
Can I use my own domain?
Yes. Set up forwarding from your domain to an Ahrara address, then add the domain in Ahrara. New addresses will use your domain instead of ahrara.dev. See the custom domain guide for setup instructions.