New:Microsoft Teams Notifications Are Now Available in Socket.Learn more →
Get Started

inboxsink

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

inboxsink

Disposable email inboxes for end-to-end tests. Waits for the message instead of sleeping, and hands you the verification code already extracted.

latest
Source
npmnpm
Version
0.1.0
Version published
Maintainers
1
Created
Source

inboxsink

Disposable email inboxes for end-to-end tests — with the verification code already extracted.

npm i inboxsink

Why

Testing a signup flow means waiting for an email. Most test suites do this:

await page.click('#signup');
await page.waitForTimeout(5000);   // 🤞

That is the single most common source of flaky CI. waitForMessage blocks until the message actually lands — no polling loop, no guessed delay — and hands you the verification code without parsing anything.

Use

import { InboxSink } from 'inboxsink';

const sink = new InboxSink(process.env.INBOXSINK_API_KEY);

const inbox = await sink.createInbox();
// { id: '42', address: '9f2c1a@mailhusk.com', expiresAt: Date }

// ... trigger the email in your app ...

const code = await sink.waitForOtp(inbox.id, { timeoutMs: 45_000 });
// '204815'

Playwright — a whole signup, code included

import { test, expect } from '@playwright/test';
import { InboxSink } from 'inboxsink';

const sink = new InboxSink();

test('a new user can sign up', async ({ page }) => {
  const inbox = await sink.createInbox({ ttlSeconds: 900 });

  await page.goto('/signup');
  await page.fill('#email', inbox.address);
  await page.click('#submit');

  const code = await sink.waitForOtp(inbox.id);   // blocks until the mail arrives
  await page.fill('#code', code);
  await page.click('#verify');

  await expect(page.getByText('Welcome')).toBeVisible();
  await sink.deleteInbox(inbox.id);
});
const link = await sink.waitForLink(inbox.id);
await page.goto(link);

The whole message

const [latest] = await sink.listMessages(inbox.id);
const full = await sink.getMessage(latest.id);
console.log(full.subject, full.text, full.html, full.attachments);

API

MethodWhat it does
createInbox({ domain?, prefix?, ttlSeconds? })New inbox. Everything is optional.
waitForMessage(id, { timeoutMs?, since? })Blocks until a message arrives. null on timeout.
waitForOtp(id, opts?)Blocks, returns the code. Throws if none arrives.
waitForLink(id, opts?)Blocks, returns the confirmation link.
listMessages(id, { since?, limit? })Summaries, newest first.
getMessage(messageId)Full message: text, html, headers, attachments.
deleteInbox(id)Deletes the inbox and its messages now.
domains()Domains available for new inboxes.

waitForOtp throws rather than returning null when a message has no code — a test should fail loudly instead of quietly submitting an empty field.

The code is only reported when the message actually announces one ("code", "verification", "sign in"…), so an invoice total or a year is never mistaken for one.

Configuration

new InboxSink('ibsk_…');                              // explicit key
new InboxSink();                                      // reads INBOXSINK_API_KEY
new InboxSink(key, { baseUrl: 'https://…' });         // self-hosted
new InboxSink(key, { fetch: myFetch });               // custom fetch

Get a key at inboxsink.com. The free tier includes 1 000 calls a month, no card.

Errors

Every failure throws InboxSinkError carrying status and code.

CodeMeaning
401Key missing, unknown or revoked
403That inbox belongs to another key
404Inbox or message gone (expired)
429Too many calls

Notes

These inboxes receive only — they cannot send. A message sent from a disposable domain is rejected or spam-filed by essentially every provider, so a "reply" button would be a button that does nothing.

Requires Node 18+ (uses the global fetch). Zero dependencies.

MIT

Keywords

email

FAQs

Package last updated on 01 Sep 2026

Related posts