python sdk for the venumzmail temp email api
Project description
VenumzMail Docs
VenumzMail's Python SDK and CLI tool. Create inboxes, read messages, extract OTPs, stream live mail, manage custom domains etc.. Everything which is possible through our API!
Contents
Install
pip install venumzmail
Auth
Pass your API key when creating a VMail instance. Keys always start with vz-.
from venumzmail import VMail
m = VMail(api_key="vz-yourkey")
No key = guest mode — tracked by IP, limited to public inboxes and basic creation. Most features require a key.
g = VMail() # guest
SDK
VMail
VMail(api_key=None, timeout=15)
| param | type | default | description |
|---|---|---|---|
api_key |
str | None | your API key, must start with vz- |
timeout |
int | 15 | request timeout in seconds |
m = VMail(api_key="vz-yourkey")
m = VMail(api_key="vz-yourkey", timeout=30)
m = VMail() # guest mode
create_inbox
Create a single inbox.
m.create_inbox(username=None, domain=None, type="private", username_length=None)
| param | type | default | description |
|---|---|---|---|
username |
str | None | custom username, random if omitted |
domain |
str | None | domain to use, random built-in if omitted |
type |
str | "private" |
"private" or "public" |
username_length |
int | None | length of random username (3–25) |
Returns an inbox object.
box = m.create_inbox()
box = m.create_inbox(username="myinbox", domain="bomboclato.store")
box = m.create_inbox(type="public")
box = m.create_inbox(username_length=15)
print(box.email) # myinbox@bomboclato.store
print(box.expires_at) # 2026-06-20T10:30:00Z
print(box.active) # True
create_inboxes
Create multiple inboxes in one call (up to 50).
m.create_inboxes(count=1, usernames=None, domain=None, type="private")
| param | type | default | description |
|---|---|---|---|
count |
int | 1 | how many inboxes to create |
usernames |
list[str] | None | custom usernames, must match count if passed |
domain |
str | None | domain for all inboxes |
type |
str | "private" |
"private" or "public" |
Returns a list of inbox objects.
boxes = m.create_inboxes(count=5)
boxes = m.create_inboxes(
count=3,
usernames=["alice", "bob", "carol"],
domain="bomboclato.store"
)
for box in boxes:
print(box.email)
list_inboxes
List all inboxes on your account.
m.list_inboxes()
Returns a list of inbox objects.
boxes = m.list_inboxes()
for box in boxes:
print(box.email, box.active)
reactivate
Extend an inbox's expiry.
m.reactivate(email)
Returns a dict with the new expires_at.
res = m.reactivate("myinbox@bomboclato.store")
print(res["expires_at"])
delete_inboxes
Delete inboxes by email list or wipe the oldest N.
m.delete_inboxes(emails=None, count=None)
Pass one of — not both.
m.delete_inboxes(emails=["a@bomboclato.store", "b@bomboclato.store"])
m.delete_inboxes(count=3) # deletes 3 oldest
get_messages
Get all messages in an inbox.
m.get_messages(email)
Returns a list of message objects (empty list if no mail yet).
msgs = m.get_messages("myinbox@bomboclato.store")
for msg in msgs:
print(msg.sender, msg.subject, msg.otp)
get_message
Get a single message by its ID.
m.get_message(message_id)
Returns a message object. Raises notFoundError if ID doesn't exist.
msg = m.get_message("48f732e8-c2e0-477e-9073-03a33d89f2cc")
print(msg.body)
print(msg.body_html)
wait_for_message
Poll an inbox until a message arrives or timeout is hit.
m.wait_for_message(email, timeout=60, poll_every=2, subject_contains=None)
| param | type | default | description |
|---|---|---|---|
email |
str | required | inbox to watch |
timeout |
int | 60 | seconds before giving up |
poll_every |
int | 2 | seconds between checks |
subject_contains |
str | None | only match messages with this in the subject |
Returns a message object or None if timed out.
msg = m.wait_for_message("myinbox@bomboclato.store")
msg = m.wait_for_message(
"myinbox@bomboclato.store",
timeout=120,
poll_every=3,
subject_contains="welcome"
)
if msg:
print(msg.sender, msg.subject)
else:
print("timed out")
wait_for_otp
Poll an inbox until a message with an OTP is found.
m.wait_for_otp(email, timeout=60, poll_every=2)
Returns the OTP as a plain string, or None if timed out.
otp = m.wait_for_otp("myinbox@bomboclato.store")
print(otp) # "482910"
stream
Live stream incoming messages for one of your own inboxes via SSE. Blocks until you break or the connection drops.
m.stream(email)
Yields message objects as they arrive.
for msg in m.stream("myinbox@bomboclato.store"):
print(msg.sender, msg.subject, msg.otp)
email_login
Read a public inbox without an API key.
VMail().email_login(email)
Returns a dict with inbox info + a messages key containing a list of message objects.
g = VMail()
data = g.email_login("public-inbox@bomboclato.store")
print(data["email"])
print(data["active"])
print(data["expires_at"])
for msg in data["messages"]:
print(msg.sender, msg.subject)
email_stream
Live stream a public inbox without an API key.
VMail().email_stream(email)
Yields message objects as they arrive.
g = VMail()
for msg in g.email_stream("public-inbox@bomboclato.store"):
print(msg.sender, msg.subject)
download_attachment
Download an attachment by its ID.
m.download_attachment(attachment_id, save_to=None, public=False)
| param | type | default | description |
|---|---|---|---|
attachment_id |
str | required | ID from message.attachments |
save_to |
str | None | file path to save to, returns path if given |
public |
bool | False | set True for attachments from public inboxes |
Returns the save path if save_to is given, otherwise raw bytes.
# save to file
m.download_attachment("uuid-here", save_to="./invoice.pdf")
# get bytes
data = m.download_attachment("uuid-here")
# public inbox attachment, no key needed
g = VMail()
g.download_attachment("uuid-here", save_to="file.pdf", public=True)
me
Get account info for the current API key.
m.me()
Returns a raw dict.
info = m.me()
print(info)
# {"email": "you@example.com", "plan": "shadow", "inboxes_used": 3, ...}
Domains
Manage custom domains on your account. Requires a paid plan.
m.add_domain(domain) # register a domain
m.list_domains() # list all registered domains
m.remove_domain(domain) # remove a domain
Before add_domain works, you need to add an MX record on your domain:
Type: MX
Host: @
Value: mail.venumzmail.xyz
Priority: 10
m.add_domain("example.com")
for d in m.list_domains():
print(d["domain"], d["status"])
m.remove_domain("example.com")
Subdomains
Create subdomains on venumzmail's built-in base domains. Requires a registered account.
m.add_subdomain(label, base_domain) # e.g. "team", "venumzmail.lol" → team.venumzmail.lol
m.list_subdomains()
m.remove_subdomain(subdomain) # full subdomain string e.g. "team.venumzmail.lol"
m.add_subdomain("team", "venumzmail.lol")
print(m.list_subdomains())
# create an inbox on your subdomain
box = m.create_inbox(domain="team.venumzmail.lol")
print(box.email) # something@team.venumzmail.lol
m.remove_subdomain("team.venumzmail.lol")
Objects
inbox
| attribute | type | description |
|---|---|---|
.email |
str | full email address |
.domain |
str | domain part |
.id |
str | unique inbox ID |
.active |
bool | whether inbox is active |
.encrypted |
bool | whether inbox is encrypted |
.expires_at |
str | ISO 8601 expiry timestamp |
.created_at |
str | ISO 8601 creation timestamp |
message
| attribute | type | description |
|---|---|---|
.id |
str | unique message ID |
.sender |
str | sender email |
.subject |
str | subject line |
.body |
str | plain text body |
.body_html |
str | HTML body |
.otp |
str or None | extracted OTP if found, else None |
.received_at |
str | ISO 8601 timestamp |
.attachments |
list[attachment] | list of attachment objects |
attachment
| attribute | type | description |
|---|---|---|
.id |
str | attachment ID (use with download_attachment) |
.filename |
str | original filename |
.size |
int | size in bytes |
.content_type |
str | MIME type e.g. application/pdf |
Errors
All errors extend venumzerror and print a colored error: + fix: hint automatically.
| error | when |
|---|---|
authError |
bad/missing key, guest trying a restricted feature |
rateLimitError |
too many requests for your plan |
notFoundError |
inbox, message, or attachment doesn't exist |
apiError |
any other 4xx/5xx — has .status_code |
from venumzmail import authError, rateLimitError, notFoundError, apiError
try:
msg = m.get_message("bad-id")
except notFoundError as e:
print(e) # prints error + fix hint
except rateLimitError:
time.sleep(2)
# retry
except authError as e:
print("check your key")
except apiError as e:
print(e.status_code)
CLI
Install
pip install venumzmail
Auth
# inline
vmail -k vz-yourkey <command>
# or set once
export x-api-key=vz-yourkey
vmail <command>
No key = guest mode.
Commands
help
Show all commands.
vmail help
me
Get account info.
vmail me
create
Create one or more inboxes.
vmail create # random
vmail create -u myinbox -d bomboclato.store # custom username + domain
vmail create -t public # public inbox
vmail create -l 15 # random 15-char username
vmail create -n 5 # bulk, 5 random inboxes
vmail create -n 3 --usernames alice bob carol -d bomboclato.store
| flag | short | description |
|---|---|---|
--username |
-u |
custom username |
--domain |
-d |
domain |
--type |
-t |
private (default) or public |
--length |
-l |
random username length |
--count |
-n |
number of inboxes |
--usernames |
space-separated names for bulk |
list
List all inboxes.
vmail list
reactivate
Extend inbox expiry.
vmail reactivate myinbox@bomboclato.store
delete
Delete inboxes.
vmail delete --emails a@bomboclato.store b@bomboclato.store
vmail delete --count 3 # deletes 3 oldest
messages
List messages in an inbox.
vmail messages myinbox@bomboclato.store
vmail messages myinbox@bomboclato.store --body # include body preview
Output per message:
[id] from=sender@x.com subject='Hello' otp=None at=2026-06-20T09:00:00Z
message
Get a single message in full.
vmail message <message-id>
wait
Block until a message arrives.
vmail wait myinbox@bomboclato.store
vmail wait myinbox@bomboclato.store --otp # return just the OTP
vmail wait myinbox@bomboclato.store --subject "verify" # filter by subject
vmail wait myinbox@bomboclato.store --timeout 120 --poll 5
| flag | default | description |
|---|---|---|
--otp |
off | extract and print just the OTP |
--subject |
none | only match messages containing this text in subject |
--timeout |
60 | seconds before giving up |
--poll |
2 | seconds between checks |
stream
Live stream messages as they arrive. Ctrl+C to stop.
vmail stream myinbox@bomboclato.store
vmail stream public-inbox@bomboclato.store --public # public inbox, no key needed
download
Download an attachment.
vmail download <attachment-id> -o ./invoice.pdf
vmail download <attachment-id> # prints byte count, doesn't save
vmail download <attachment-id> --public # public inbox attachment
login
Read a public inbox without a key.
vmail login public-inbox@bomboclato.store
domains
Manage custom domains (paid plan only).
vmail domains # list
vmail domains --add example.com
vmail domains --remove example.com
subdomains
Manage subdomains on built-in base domains.
vmail subdomains # list
vmail subdomains --add team venumzmail.lol # creates team.venumzmail.lol
vmail subdomains --remove team.venumzmail.lol
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file venumzmail-0.1.0.tar.gz.
File metadata
- Download URL: venumzmail-0.1.0.tar.gz
- Upload date:
- Size: 17.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
998b806ef9018b5248c2cd5b54ad6cd120dddfe4a3fd31a064352bab68a2818b
|
|
| MD5 |
7e48e0e722fafa6da3cab745e40388b4
|
|
| BLAKE2b-256 |
82cd64cab393088eea67288881007959ef0810008914e3e41ee32b26d3fa0ac6
|
File details
Details for the file venumzmail-0.1.0-py3-none-any.whl.
File metadata
- Download URL: venumzmail-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb9c54fd2ba84e8ca4ef4dde09ad86d833bc50197fca73c1be1ce876653a129c
|
|
| MD5 |
6f8bb797980c0e3fb91f8e92441783c8
|
|
| BLAKE2b-256 |
646dc08e9c0e4ddf27935a44edf0859cc04a21b4b6784ec74035a39996eea22c
|