Updates

Product releases, engineering notes, and platform upgrades from the plop.email team.

Product

TypeScript and Python SDKs are here

TypeScript and Python SDKs are here

Testing email flows just got a lot simpler. We're releasing official SDKs for TypeScript and Python — designed to replace the boilerplate of polling loops, manual fetch calls, and untyped JSON parsing.

#The problem with raw API calls

Every team using Plop for E2E tests ends up writing the same helper:

// Every project has a version of this
async function waitForEmail(to, timeout = 10000) {
  const start = Date.now();
  while (Date.now() - start < timeout) {
    const res = await fetch(`https://api.plop.email/v1/messages/latest?to=${to}`, {
      headers: { Authorization: `Bearer ${process.env.PLOP_API_KEY}` },
    });
    if (res.ok) return (await res.json()).data;
    await new Promise(r => setTimeout(r, 1000));
  }
  throw new Error("Timeout");
}

It works, but it's repetitive, untyped, and easy to get wrong (error handling, timeout edge cases, race conditions with since timestamps).

#One line instead

#TypeScript

npm install @plop-email/sdk
import { Plop } from "@plop-email/sdk";

const plop = new Plop(); // reads PLOP_API_KEY from env

const email = await plop.messages.waitFor(
  { mailbox: "qa", tag: "verification" },
  { timeout: 30_000 },
);

const otp = email.textContent?.match(/\d{6}/)?.[0];

That's it. waitFor polls the API, handles 404s, respects the timeout, and returns a fully typed MessageDetail object. If nothing arrives, it throws a PlopError.

#Python

pip install plop-sdk
from plop_sdk import Plop

plop = Plop()  # reads PLOP_API_KEY from env

email = plop.messages.wait_for(
    mailbox="qa",
    tag="verification",
    timeout=30,
)

import re
otp = re.search(r"\d{6}", email.text_content).group()

Sync and async clients included. AsyncPlop works with pytest-asyncio and async with context managers.

#What's included

Both SDKs cover the full Plop API:

FeatureTypeScriptPython
List mailboxesplop.mailboxes.list()plop.mailboxes.list()
List/filter messagesplop.messages.list({...})plop.messages.list(...)
Get message by IDplop.messages.get(id)plop.messages.get(id)
Get latest matchplop.messages.latest({...})plop.messages.latest(...)
Poll for emailplop.messages.waitFor(...)plop.messages.wait_for(...)
Verify webhooksplop.webhooks.verify(...)plop.webhooks.verify(...)
Create/update/delete mailboxesplop.mailboxes.create(...)plop.mailboxes.create(...)
Delete messagesplop.messages.delete(id)plop.messages.delete(id)
Stream messages (SSE)plop.messages.stream(...)plop.messages.stream(...)
Manage webhooksplop.webhooks.create(...)plop.webhooks.create(...)
List webhook deliveriesplop.webhooks.deliveries(id)plop.webhooks.deliveries(id)
Rotate API keyplop.apiKeys.rotate()plop.api_keys.rotate()
Cursor paginationafter_id + has_moreafter_id + has_more

#Design decisions

Zero runtime dependencies (TypeScript) — uses native fetch and crypto. No axios, no node-fetch. Works everywhere Node 18+ runs.

httpx + Pydantic (Python) — sync and async HTTP with typed Pydantic models. Every response field has a proper Python type.

{data, error} pattern (TypeScript) — inspired by Resend. Methods never throw; you destructure the result. Exception: waitFor throws on timeout since it's typically used in test contexts where throwing is natural.

Typed exceptions (Python) — PlopAuthError, PlopForbiddenError, PlopNotFoundError, PlopTimeoutError. Catch exactly what you need.

#Get started

# TypeScript
npm install @plop-email/sdk

# Python
pip install plop-sdk

Set your PLOP_API_KEY environment variable and you're ready. Both SDKs auto-detect the key from the environment.

Product

Webhooks are live

Webhooks are live

You can now receive real-time webhook notifications when emails land in your mailbox. No more polling.

#How it works

Register an HTTPS endpoint in Settings → Webhooks. When a new email arrives, plop sends a POST request with the message metadata:

{
  "event": "email.received",
  "timestamp": "2026-02-06T12:00:00.000Z",
  "data": {
    "id": "msg_abc123",
    "mailbox": "qa",
    "mailboxWithTag": "qa+signup",
    "tag": "signup",
    "from": "sender@example.com",
    "to": "qa+signup@in.plop.email",
    "subject": "Welcome to Acme",
    "receivedAt": "2026-02-06T11:59:58.000Z",
    "domain": "in.plop.email"
  }
}

#Signed payloads

Every request includes an X-Plop-Signature header so you can verify the payload was sent by plop and hasn't been tampered with:

import { createHmac, timingSafeEqual } from "node:crypto";

const [tPart, v1Part] = header.split(",");
const timestamp = tPart.replace("t=", "");
const receivedSig = v1Part.replace("v1=", "");

const expected = createHmac("sha256", secret)
  .update(`${timestamp}.${body}`)
  .digest("hex");

const valid = timingSafeEqual(
  Buffer.from(expected),
  Buffer.from(receivedSig),
);

#Retries and delivery logs

Failed deliveries are retried up to 3 times with exponential backoff. You can inspect every attempt — status code, latency, and error — in the delivery logs under Settings → Webhooks.

#Plan availability

Webhooks are available on Team plans and above. Read the docs for the full setup guide.

Product

Introducing plop.email: inbox automation for teams

Introducing plop.email: inbox automation for teams

Email touches almost every workflow: onboarding, password resets, invoices, support, and long-tail alerts. Yet most teams still debug inboxes manually or maintain brittle test scripts. plop.email turns inbound email into structured data with a first-class API and UI.

#What plop.email does

  • Routes inbound email into mailboxes and tags.
  • Stores raw and normalised content for reliable access.
  • Exposes a simple Messages API for automation.
  • Supports mailbox + tag routing for teams and environments.

#Built for production and for tests

Plop works in both the product and the pipeline. You can route live notifications into a support mailbox, and you can also pull the latest test email in CI with a single API call.

#Why we built it

We needed a system that made email reliable for automated workflows without standing up a full mail stack. That meant clear routing rules, deterministic access, and zero guesswork when something fails.

If your team relies on email anywhere in your stack, plop.email helps you keep it boring, fast, and visible.

Guides

Mailbox + tag addressing for deterministic tests

Mailbox + tag addressing for deterministic tests

Plop uses a simple address pattern to keep your email flows deterministic. You can route multiple flows into the same mailbox and distinguish them by tag.

#The pattern

Use mailbox+tag@in.plop.email.

Examples:

  • qa+signup@in.plop.email
  • qa+login@in.plop.email
  • billing+invoice@in.plop.email

All messages for qa+* land in the qa mailbox. Tags let you isolate flows without creating dozens of mailboxes.

#Why it matters

Tests need a consistent target. When each flow has its own tag, your API calls become stable and you avoid fuzzy matching on subject lines.

#Suggested usage

  1. Pick a mailbox per environment (qa, staging, prod).
  2. Use tags for each flow (signup, reset, invite).
  3. Fetch the latest message by mailbox + tag in your tests.

That is it. No more inbox hunting.

Engineering

Messages API basics: latest, list, and filters

Messages API basics: latest, list, and filters

The Messages API is designed for automation. It gives you predictable access to inbound email without scraping an inbox UI.

#Core endpoints

EndpointDescription
GET /v1/messages/latestFetch the newest message for a mailbox + tag
GET /v1/messagesList messages with filters
GET /v1/messages/:idFetch a specific message by id

#Example: latest message

curl "https://api.plop.email/v1/messages/latest?mailbox=qa&tag=signup"

#Example: list with filters

curl "https://api.plop.email/v1/messages?mailbox=qa&tag=signup&limit=10"
  • Use latest for E2E tests and health checks.
  • Use lists for dashboards or workflow automation.
  • Store message ids in your workflow logs for traceability.

If you need a new filter or payload field, tell us. We design this API around real workflows, not theoretical mail clients.

Security

Security, access controls, and retention

Security, access controls, and retention

Email often contains sensitive information. Plop is built around access controls, auditability, and minimal retention.

#Security principles

  • Least-privilege access for accounts and API keys.
  • Explicit mailbox permissions for teams.
  • Clear audit trails for inbound messages and access.

#Retention controls

Retention is set by plan: Starter retains messages for 14 days, Pro retains messages for 90 days, and Enterprise retention is defined by agreement. Messages older than the retention window are deleted and no longer accessible through the API or app.

#What we do not do

  • We do not read message content for ad targeting.
  • We do not sell personal data.
  • We do not expose your inbox data to third parties without consent.

If you need a specific compliance review, contact us and we will share our security posture and architecture details.

Roadmap

What we are building next

What we are building next

Plop is focused on making inbox automation effortless. Here is what we are shipping next.

#Shipped

  • Signed webhooks for tamper protection.
  • Webhook delivery retries with visibility into failures.

#Near term

  • Per-mailbox rate limits and usage alerts.
  • Faster message search with saved filters.

#In progress

  • Structured extraction presets for common email types.
  • Message diffing for multi-step flows.

#Longer term

  • Built-in inbox replay for staging environments.
  • Cross-mailbox correlation for complex workflows.
  • Team-level audit exports.

If you have a workflow that plop.email should support, tell us. We are building this product alongside teams who live in inboxes every day.