Python SDK
Install and use the official Plop Python SDK for email testing and polling.
The plop-sdk package provides sync and async clients for the Plop API. It uses httpx for HTTP and pydantic for typed responses.
Installation
pip install plop-sdkQuick start
from plop_sdk import Plop
plop = Plop() # reads PLOP_API_KEY env var
# List mailboxes
mailboxes = plop.mailboxes.list()
# Fetch latest message
latest = plop.messages.latest(mailbox="qa", tag="signup")
print(latest.subject)
print(latest.text_content)Wait for an email
The wait_for method polls the API until a matching message arrives or the timeout expires:
email = plop.messages.wait_for(
mailbox="qa",
tag="verification",
timeout=30, # seconds
interval=1.0, # poll interval
)
import re
otp = re.search(r"\d{6}", email.text_content).group()Raises PlopTimeoutError if no match is found within the timeout.
pytest example
import pytest
from plop_sdk import Plop
@pytest.fixture
def plop():
return Plop()
def test_welcome_email(plop):
# trigger your app to send the email, then:
email = plop.messages.wait_for(
mailbox="qa",
tag="welcome",
timeout=30,
)
assert "Welcome" in email.subject
assert "Get Started" in email.html_contentAsync client
import asyncio
from plop_sdk import AsyncPlop
async def main():
async with AsyncPlop() as plop:
email = await plop.messages.wait_for(
mailbox="qa", tag="login",
)
print(email.subject)
asyncio.run(main())List and filter messages
messages = plop.messages.list(
mailbox="qa",
tag="login",
since="2026-01-01T00:00:00Z",
limit=10,
)
for msg in messages:
print(f"{msg.from_address}: {msg.subject}")Get a message by ID
message = plop.messages.get("uuid-here")
print(message.html_content)Verify webhook signatures
is_valid = plop.webhooks.verify(
secret="whsec_...",
signature=request.headers["x-plop-signature"],
body=raw_body,
)Manage mailboxes
mailbox = plop.mailboxes.create(name="staging")
plop.mailboxes.update(mailbox.id, name="staging-v2")
plop.mailboxes.delete(mailbox.id)Delete a message
result = plop.messages.delete("uuid-here")Stream messages (SSE)
for message in plop.messages.stream(mailbox="qa"):
print(f"New: {message.subject} from {message.from_address}")Manage webhooks
created = plop.webhooks.create(url="https://example.com/webhook")
print(created.secret) # shown once
endpoints = plop.webhooks.list()
plop.webhooks.toggle(endpoints[0].id, active=False)Rotate API key
result = plop.api_keys.rotate()
print(result.key) # new key — update your envError handling
Methods raise typed exceptions:
from plop_sdk import Plop, PlopAuthError, PlopNotFoundError
plop = Plop()
try:
message = plop.messages.get("nonexistent-id")
except PlopNotFoundError:
print("Message not found")
except PlopAuthError:
print("Invalid API key")| Exception | HTTP Status |
|---|---|
PlopAuthError | 401 |
PlopForbiddenError | 403 |
PlopNotFoundError | 404 |
PlopTimeoutError | — (polling timeout) |
Configuration
plop = Plop(
api_key="plop_...", # or set PLOP_API_KEY env var
base_url="https://api.plop.email", # default
)API reference
| Method | Description |
|---|---|
plop.mailboxes.list(**params) | List mailboxes |
plop.messages.list(**params) | List messages with filters |
plop.messages.get(id) | Get message by ID |
plop.messages.latest(**params) | Get most recent matching message |
plop.messages.wait_for(**params) | Poll until a message arrives |
plop.mailboxes.create(name=...) | Create a mailbox |
plop.mailboxes.update(id, name=...) | Rename a mailbox |
plop.mailboxes.delete(id) | Delete a mailbox |
plop.messages.delete(id) | Delete a message |
plop.messages.stream(**params) | Stream new messages (SSE) |
plop.webhooks.list() | List webhook endpoints |
plop.webhooks.create(url=...) | Create a webhook endpoint |
plop.webhooks.delete(id) | Delete a webhook endpoint |
plop.webhooks.toggle(id, active=...) | Enable/disable a webhook |
plop.webhooks.deliveries(id) | List webhook deliveries |
plop.webhooks.verify(**opts) | Verify webhook HMAC signature |
plop.api_keys.rotate() | Rotate the current API key |