9.0 KiB
Mail API
Mailbox password login
ADDRESS_PASSWORD_LOGIN_ONLY defaults to false and only takes effect with ENABLE_ADDRESS_PASSWORD=true. It rejects legacy credentials for login and API access, and hides credential displays and automatic login links. Legacy credential links also fail API authentication. Existing mailboxes without passwords need a bound user or administrator to set one; no database migration is needed.
- Password login issues a 30-day JWT with
type: "address_password_login",address,address_id,iat, andexp. Mailbox APIs retainAuthorization: Bearer <jwt>and use middleware for authentication. GET /api/settingsreturns this login information,send_balance, andnew_address_token. A valid JWT with less than 7 days remaining receives a new 30-day token; otherwise the field isnull. Expired JWTs require login again, and legacy credentials cannot obtain new tokens.- When loading settings, the frontend validates the new token with another settings request before replacing the current token. Ordinary requests do not refresh tokens. External clients should also save
new_address_token; the switch rejects legacy credentials used directly by SMTP/IMAP and Agent clients. - The local cache uses server-returned mailbox information without decoding JWTs and retains both login methods independently. Historical token-only entries display “Saved mailbox” until selected and validated. Password-only login hides identified legacy entries without deleting them.
- Mailbox creation and authorized access through user accounts, administrators, and Telegram issue mailbox JWTs according to the switch. Telegram KV stores separate permanent
telegram_bindingtokens, which mailbox APIs reject. Expiration is ignored only for historical stored bindings accessed after Telegram identity verification; tokens submitted for new bindings must pass mailbox authentication.
Reset a bound mailbox password
With ENABLE_ADDRESS_PASSWORD enabled, the user center offers password reset without the previous password:
POST /user_api/address/:address_id/reset_password
x-user-token: <user JWT>
Content-Type: application/json
{"new_password":"<64-character lowercase SHA-256 hex digest of the new password>"}
A single SQL statement checks that the user exists and owns the binding, updating only the existing password and update time. Success returns {"success":true}; missing authentication returns 401, an unbound mailbox or disabled feature returns 403, and invalid input returns 400. Resetting a password does not revoke existing JWTs; valid JWTs can still renew. No session table or revocation state is added.
Viewing Emails via Mail API
This is a python example using the requests library to view emails.
limit = 10
offset = 0
res = requests.get(
f"https://<your-worker-address>/api/mails?limit={limit}&offset={offset}",
headers={
"Authorization": f"Bearer {your-JWT-password}",
# "x-custom-auth": "<your-website-password>", # If private site password is enabled
"Content-Type": "application/json"
}
)
Note: /api/mails returns raw RFC822 data by design (for example source/raw), and it does not guarantee parsed fields such as subject, text, or html. Parse the raw source on the client side (for example with mail-parser-wasm or postal-mime) if you need readable message content.
Admin Mail API
Supports address filter
import requests
url = "https://<your-worker-address>/admin/mails"
querystring = {
"limit":"20",
"offset":"0",
# address is optional parameter
"address":"xxxx@awsl.uk"
}
headers = {
"x-admin-auth": "<your-Admin-password>",
# "x-custom-auth": "<your-website-password>", # If private site password is enabled
}
response = requests.get(url, headers=headers, params=querystring)
print(response.json())
Note: /admin/mails follows the same design as /api/mails: it returns stored raw MIME data. If you need readable subject/body, parse the raw content on the client side.
Note: Keyword filtering has been removed from the backend API. If you need to filter emails by content, please use the frontend filter input in the UI, which filters the currently displayed page.
Mail Read Status API
Enable ENABLE_MAIL_READ_STATUS and upgrade the database first. Historical mail has is_unread = NULL and is treated as read; new mail has is_unread = 1. Opening unread mail from the web mail list marks it as read, and its detail view can switch the state manually. Refreshing the page does not mark it as read:
PATCH /api/mails/:id/read: set one mail belonging to the current address; use{ "isUnread": true }for unread or{ "isUnread": false }for read
Admin Get Mail API
Fetch a single mail by mail ID without a mailbox JWT. Authenticate with x-admin-auth.
The response matches one entry returned by /admin/mails: gzip-compressed raw content is decompressed into raw, and raw_blob is excluded.
import requests
mail_id = 1
url = f"https://<your-worker-address>/admin/mails/{mail_id}"
headers = {
"x-admin-auth": "<your-Admin-password>",
# "x-custom-auth": "<your-website-password>", # If private site password is enabled
}
response = requests.get(url, headers=headers)
print(response.json())
Admin Delete Mail API
Delete a single mail by mail ID.
import requests
mail_id = 1
url = f"https://<your-worker-address>/admin/mails/{mail_id}"
headers = {
"x-admin-auth": "<your-Admin-password>",
# "x-custom-auth": "<your-website-password>", # If private site password is enabled
}
response = requests.delete(url, headers=headers)
print(response.json())
Admin Delete Address API
Delete an email address by address ID (also deletes associated mails, sender permissions, and user bindings).
import requests
address_id = 1
url = f"https://<your-worker-address>/admin/delete_address/{address_id}"
headers = {
"x-admin-auth": "<your-Admin-password>",
# "x-custom-auth": "<your-website-password>", # If private site password is enabled
}
response = requests.delete(url, headers=headers)
print(response.json())
Admin Clear Inbox API
Clear all received mails for an address by address ID.
import requests
address_id = 1
url = f"https://<your-worker-address>/admin/clear_inbox/{address_id}"
headers = {
"x-admin-auth": "<your-Admin-password>",
# "x-custom-auth": "<your-website-password>", # If private site password is enabled
}
response = requests.delete(url, headers=headers)
print(response.json())
Admin Clear Sent Items API
Clear all sent mails for an address by address ID.
import requests
address_id = 1
url = f"https://<your-worker-address>/admin/clear_sent_items/{address_id}"
headers = {
"x-admin-auth": "<your-Admin-password>",
# "x-custom-auth": "<your-website-password>", # If private site password is enabled
}
response = requests.delete(url, headers=headers)
print(response.json())
User Mail API
::: warning Note: User JWT vs Address JWT
This endpoint uses User JWT (obtained via /user_api/login or /user_api/register), with x-user-token header.
Do not confuse with Address JWT:
- Address JWT uses
Authorization: Bearer <jwt>to access/api/*endpoints - User JWT uses
x-user-token: <jwt>to access/user_api/*endpoints :::
Bound Address List
GET /user_api/bind_address uses server-side pagination and accepts these query parameters:
Requests without pagination parameters return the default first page. Fetching all bound addresses in one request is not supported.
| Parameter | Default | Description |
|---|---|---|
limit |
20 |
Page size, from 1 to 100 |
offset |
0 |
Pagination offset |
The results array contains only the current page. The total is queried only when offset=0; later pages return count: 0, so clients should retain the total from the first page.
import requests
url = "https://<your-worker-address>/user_api/bind_address"
headers = {
"x-user-token": "<your-user-JWT-token>",
}
querystring = {
"limit": "20",
"offset": "0",
}
response = requests.get(url, headers=headers, params=querystring)
print(response.json())
User Mail List
Supports address filter
import requests
url = "https://<your-worker-address>/user_api/mails"
querystring = {
"limit":"20",
"offset":"0",
# address is optional parameter
"address":"xxxx@awsl.uk"
}
headers = {
"x-user-token": "<your-user-JWT-token>",
# "x-custom-auth": "<your-website-password>", # If private site password is enabled
}
response = requests.get(url, headers=headers, params=querystring)
print(response.json())
Note: /user_api/mails also returns raw RFC822 content from storage; parse it in your client to extract subject, text, and html.
Note: Keyword filtering has been removed from the backend API. If you need to filter emails by content, please use the frontend filter input in the UI, which filters the currently displayed page.