Files
mailcow-dockerized/data/web/api/openapi.yaml
T

14494 lines
462 KiB
YAML

openapi: 3.1.0
info:
description: >-
The API of mailcow, the mail server suite with antispam, antivirus and a
web UI.
**API keys**: create them in the mailcow UI under System > Configuration >
Access > Administrators, card API. A key works from its allowed IP
addresses (or from anywhere if the IP check is skipped). Read-only keys
may use the `get` routes only. Keys set in mailcow.conf (`API_KEY`,
`API_KEY_READ_ONLY`, `API_ALLOW_FROM`) are shown in the UI but can only be
changed in mailcow.conf. A key acts as an administrator.
**Requests**: `get` routes use GET, all others POST with
`Content-Type: application/json`.
- add: the new object as body
- edit: `{"items": [...], "attr": {...}}`, `items` are the objects to
change, `attr` the values to set
- delete: the list of objects to delete
**Answers**: write routes return the list of messages of the call
(`type`, `msg`), or `{"type": "success", "msg": "Task completed"}` /
`{"type": "error", "msg": "Cannot add item"}` if there are none. The
status is 200 for failures too, so check `type`. Read routes return the
object or list, `{}` or `[]` if there is nothing. Unknown routes answer
404, invalid JSON 400, a wrong method 405.
title: mailcow API
version: "1.0.0"
servers:
- url: /
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
schemas:
Message:
type: object
description: >-
One message of a write call, as the mailcow UI shows it. `msg` is a key
of the mailcow language files, alone or as a list with the values of its
placeholders.
properties:
type:
type: string
enum:
- success
- danger
- warning
- info
log:
type: array
description: >-
The call that produced the message (function, action, object,
data), secrets replaced by `*`
items: {}
msg:
oneOf:
- type: string
- type: array
items: {}
required:
- type
- msg
Messages:
type: array
items:
$ref: "#/components/schemas/Message"
TaskResult:
type: object
description: Answer of a write call that produced no message
properties:
type:
type: string
enum:
- success
- error
msg:
type: string
examples:
- Task completed
- Cannot add item
required:
- type
- msg
Error:
type: object
properties:
type:
type: string
const: error
msg:
type: string
required:
- type
- msg
Domain:
type: object
description: >-
A domain. Quotas and sizes are in bytes; the `*_int` fields repeat the
value before them.
properties:
domain_name:
type: string
description: Domain name (IDN as punycode)
domain_h_name:
type: string
description: Domain name in Unicode
description:
type: string
description: Description
max_new_mailbox_quota:
type: integer
description: >-
Largest quota a new mailbox can get: the free domain quota, at most
the max. mailbox quota
def_new_mailbox_quota:
type: integer
description: Quota a new mailbox gets by default
quota_used_in_domain:
type: [string, integer]
description: Sum of the quotas of the mailboxes
bytes_total:
type: [string, integer]
description: Storage used by the mailboxes
msgs_total:
type: [string, integer]
description: Number of messages in the mailboxes
mboxes_in_domain:
type: integer
description: Number of mailboxes
mboxes_left:
type: integer
description: Mailboxes that can still be added
max_num_aliases_for_domain:
type: integer
description: Max. number of aliases
max_num_mboxes_for_domain:
type: integer
description: Max. number of mailboxes
def_quota_for_mbox:
type: integer
description: Default quota of new mailboxes
max_quota_for_mbox:
type: integer
description: Max. quota per mailbox
max_quota_for_domain:
type: integer
description: Quota of the whole domain
relayhost:
type: [string, integer]
description: ID of the sender-dependent transport, "0" = none
backupmx:
type: integer
enum: [0, 1]
description: Relay domain (backup MX)
backupmx_int:
type: integer
enum: [0, 1]
gal:
type: integer
enum: [0, 1]
description: Global address list in SOGo
gal_int:
type: integer
enum: [0, 1]
rl:
description: Rate limit, `false` if none
oneOf:
- $ref: "#/components/schemas/DomainRatelimit"
- type: boolean
const: false
active:
type: integer
enum: [0, 1]
description: Domain active
active_int:
type: integer
enum: [0, 1]
relay_all_recipients:
type: integer
enum: [0, 1]
description: Relay all recipients
relay_all_recipients_int:
type: integer
enum: [0, 1]
relay_unknown_only:
type: integer
enum: [0, 1]
description: Relay non-existing mailboxes only
relay_unknown_only_int:
type: integer
enum: [0, 1]
created:
type: string
description: Creation time (`YYYY-MM-DD hh:mm:ss`)
modified:
type: [string, "null"]
description: Time of the last change
aliases_in_domain:
type: [integer, string]
description: Number of aliases, including those of its alias domains
aliases_left:
type: integer
description: Aliases that can still be added
domain_admins:
type: string
description: Comma-separated domain admins, `-` if none; admins only
tags:
type: array
items:
type: string
description: Tags; missing when the domain has none
DomainRatelimit:
type: object
description: Rate limit of a domain or alias domain
properties:
value:
type: string
description: Messages per time frame
frame:
type: string
enum: [s, m, h, d]
description: Time frame (second, minute, hour, day)
DomainTemplate:
type: object
properties:
id:
type: integer
description: Template ID
template:
type: string
description: Template name
type:
type: string
const: domain
attributes:
$ref: "#/components/schemas/DomainTemplateAttributes"
created:
type: string
description: Creation time
modified:
type: [string, "null"]
description: Time of the last change
DomainTemplateAttributes:
type: object
description: Values of a domain template as stored; quotas in bytes
properties:
tags:
type: array
items:
type: string
max_num_aliases_for_domain:
type: integer
max_num_mboxes_for_domain:
type: integer
def_quota_for_mbox:
type: integer
max_quota_for_mbox:
type: integer
max_quota_for_domain:
type: integer
rl_frame:
type: string
enum: [s, m, h, d]
rl_value:
type: [string, integer]
description: Rate limit, "" = none
active:
type: integer
enum: [0, 1]
gal:
type: integer
enum: [0, 1]
backupmx:
type: integer
enum: [0, 1]
relay_all_recipients:
type: integer
enum: [0, 1]
relay_unknown_only:
type: integer
enum: [0, 1]
dkim_selector:
type: string
key_size:
type: integer
DomainTemplateInput:
type: object
description: >-
Values of a domain template, quotas in MiB. The defaults apply when a
template is added; for edit/domain/template see there.
properties:
template:
type: string
description: Template name, unique
tags:
type: array
items:
type: string
default: []
description: Tags of new domains
max_num_aliases_for_domain:
type: [integer, string]
default: 400
description: Max. number of aliases
max_num_mboxes_for_domain:
type: [integer, string]
default: 10
description: Max. number of mailboxes
def_quota_for_mbox:
type: [integer, string]
default: 3072
description: Default quota of new mailboxes in MiB
max_quota_for_mbox:
type: [integer, string]
default: 10240
description: Max. quota per mailbox in MiB
max_quota_for_domain:
type: [integer, string]
default: 10240
description: Quota of the whole domain in MiB
rl_value:
type: [integer, string]
default: ""
description: Rate limit, messages per `rl_frame`; empty = none
rl_frame:
type: string
enum: [s, m, h, d]
default: s
description: Rate limit time frame
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 1
gal:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 1
description: Global address list in SOGo
backupmx:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: Relay domain (backup MX)
relay_all_recipients:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
relay_unknown_only:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
dkim_selector:
type: string
default: dkim
description: Selector of the DKIM key of new domains
key_size:
type: [integer, string]
default: 2048
description: DKIM key size in bits of new domains
AliasDomain:
type: object
properties:
alias_domain:
type: string
description: Alias domain name
target_domain:
type: string
description: Domain the alias domain points to
parent_is_backupmx:
type: integer
enum: [0, 1]
description: The target domain is a relay domain
active:
type: integer
enum: [0, 1]
description: Alias domain active
active_int:
type: integer
enum: [0, 1]
rl:
description: Rate limit, `false` if none
oneOf:
- $ref: "#/components/schemas/DomainRatelimit"
- type: boolean
const: false
created:
type: string
description: Creation time
modified:
type: [string, "null"]
description: Time of the last change
DomainPolicyEntry:
type: object
properties:
object:
type: string
description: The domain or mailbox the entry belongs to
value:
type: string
description: Sender address or pattern
prefid:
type: integer
description: Entry ID (for delete/domain-policy)
DkimKey:
type: object
properties:
pubkey:
type: string
description: Public key (base64, without PEM lines)
length:
type: string
enum: ["1024", "2048", "3072", "4096", ">= 8192"]
description: Key size in bits, estimated from the public key
dkim_txt:
type: string
description: >-
Content of the DNS TXT record; split into quoted strings of 255
characters when `SPLIT_DKIM_255` is enabled
dkim_selector:
type: string
description: Selector
privkey:
type: string
description: >-
Private key in PEM format, base64-encoded, when
`SHOW_DKIM_PRIV_KEYS` is enabled, else empty
DomainSearchRequest:
type: object
description: >-
Server-side processing parameters of DataTables
(https://datatables.net/manual/server-side). Without `start` and
`length` all matching domains are answered.
properties:
draw:
type: integer
description: Request counter, answered as it is
start:
type: integer
description: Offset of the first domain
length:
type: integer
description: Number of domains, -1 = all
search:
type: object
properties:
value:
type: string
description: Searched in all columns with `searchable` true
order:
type: array
items:
type: object
properties:
column:
type: integer
description: Position in `columns` (see the description of the route)
dir:
type: string
enum: [asc, desc]
columns:
type: array
description: >-
The columns of the table; the position gives the database column
(see the description of the route)
items:
type: object
properties:
data:
type: [string, integer]
description: >-
Column name of the UI; a column position makes
`search.value` of this entry filter that column
searchable:
type: [boolean, string]
description: Column takes part in the global search; must be set
orderable:
type: [boolean, string]
description: Column may be sorted by; must be set
search:
type: object
properties:
value:
type: string
description: Filter of this column
DomainSearchResult:
type: object
properties:
draw:
type: integer
description: "`draw` of the request"
recordsTotal:
type: integer
description: Number of domains the caller can see
recordsFiltered:
type: integer
description: Number of domains that match the search
data:
type: array
description: The domains of the page
items:
$ref: "#/components/schemas/Domain"
MailboxItems:
description: One mailbox address or a list of them
oneOf:
- type: string
- type: array
items:
type: string
UserAclName:
type: string
description: "A user ACL: something the mailbox user may do in the UI"
enum:
- spam_alias
- tls_policy
- spam_score
- spam_policy
- delimiter_action
- syncjobs
- eas_reset
- sogo_profile_reset
- pushover
- quarantine
- quarantine_attachments
- quarantine_notification
- quarantine_category
- app_passwds
- pw_reset
ProtocolAccessName:
type: string
enum:
- imap
- pop3
- smtp
- sieve
- eas
- dav
MailboxAttributes:
type: object
description: Settings of a mailbox; flags are "0" or "1"
properties:
force_pw_update:
type: [string, integer]
description: The user must change the password at the next login
force_tfa:
type: [string, integer]
description: The user must set up two-factor authentication at the next login
tls_enforce_in:
type: [string, integer]
tls_enforce_out:
type: [string, integer]
sogo_access:
type: [string, integer]
description: Login to SOGo from the UI
imap_access:
type: [string, integer]
pop3_access:
type: [string, integer]
smtp_access:
type: [string, integer]
sieve_access:
type: [string, integer]
eas_access:
type: [string, integer]
dav_access:
type: [string, integer]
relayhost:
type: [string, integer]
description: ID of the sender-dependent transport, "0" for none
shared:
type: [string, integer]
description: Shared mailbox without a login of its own
passwd_update:
type: [string, integer]
description: Time of the last password change
mailbox_format:
type: string
quarantine_notification:
type: string
enum:
- never
- hourly
- daily
- weekly
quarantine_category:
type: string
enum:
- reject
- add_header
- all
attribute_hash:
type: string
description: Hash of the template the settings came from, cleared by manual changes
recovery_email:
type: string
description: Address for password reset mails (present after it was set)
template:
type: string
description: Name of the template the mailbox was created from (if any)
Mailbox:
type: object
description: >-
A mailbox. The reduced form lacks `max_new_quota`, `spam_aliases`,
`pushover_active`, `rl`, `rl_scope`, `is_relayed` and `sender_acl`;
`tags` is missing without tags.
properties:
username:
type: string
description: Address of the mailbox
active:
type: integer
description: 1 active, 0 inactive, 2 login disabled (mail is still accepted)
active_int:
type: integer
description: Same as `active`
domain:
type: string
name:
type: string
description: Full name
local_part:
type: string
quota:
type: integer
description: Quota in bytes, 0 = unlimited
messages:
type: integer
description: Number of messages
attributes:
$ref: "#/components/schemas/MailboxAttributes"
custom_attributes:
type: [object, array]
description: Custom attributes (an empty list when there are none)
additionalProperties:
type: string
quota_used:
type: integer
description: Used bytes
percent_in_use:
type: [integer, string]
description: Used part of the quota in percent, "- " for unlimited quota
created:
type: string
modified:
type: [string, "null"]
authsource:
type: string
enum:
- mailcow
- keycloak
- generic-oidc
- ldap
percent_class:
type: string
enum:
- info
- success
- warning
- danger
description: info (unlimited), success, warning (≥ 75 %), danger (≥ 90 %)
last_imap_login:
type: integer
description: Unix time of the last IMAP login, 0 = none
last_smtp_login:
type: integer
last_pop3_login:
type: integer
last_sso_login:
type: integer
last_sogo_login:
type: integer
max_new_quota:
type: integer
description: Largest quota in bytes the mailbox may get (domain limits)
spam_aliases:
type: integer
description: Number of valid time-limited aliases
pushover_active:
type: integer
enum: [0, 1]
rl:
description: Effective rate limit, `false` if there is none
oneOf:
- $ref: "#/components/schemas/MailboxRatelimit"
- type: boolean
const: false
rl_scope:
type: string
enum:
- mailbox
- domain
description: Whether `rl` is the mailbox's own limit or the domain limit
is_relayed:
type: integer
description: 1 if the domain is relayed (backup MX)
sender_acl:
type: array
description: Internal addresses and @domains the mailbox may send as
items:
type: string
tags:
type: array
items:
type: string
MailboxAdd:
type: object
required:
- local_part
- domain
properties:
local_part:
type: string
description: Part before the @
domain:
type: string
description: Domain of the mailbox
name:
type: string
description: Full name (`<` and `>` at the ends are removed)
authsource:
type: string
enum:
- mailcow
- keycloak
- generic-oidc
- ldap
default: mailcow
description: Login source; an external one only if it is the configured identity provider, else mailcow
password:
type: string
format: password
description: Checked against the password policy; empty (with `password2`) for a shared mailbox
password2:
type: string
format: password
description: The password again
template:
type: [integer, string]
description: ID of the mailbox template for the defaults (default the first)
quota:
type: [integer, string]
description: Quota in MiB, 0 = unlimited
active:
type: [integer, string]
enum: [0, 1, 2, "0", "1", "2"]
description: 1 active, 0 inactive, 2 login disabled (mail is accepted)
tags:
type: array
items:
type: string
description: Tags (the first 26 are saved)
protocol_access:
type: array
description: Allowed protocols; when sent it replaces the single `*_access` fields
items:
$ref: "#/components/schemas/ProtocolAccessName"
imap_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
pop3_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
smtp_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
sieve_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
eas_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
dav_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
sogo_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Login to SOGo from the UI
force_pw_update:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Password change at the first login (always 0 for external sources)
force_tfa:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Two-factor setup at the first login (always 0 for generic-oidc)
tls_enforce_in:
type: [integer, string]
enum: [0, 1, "0", "1"]
tls_enforce_out:
type: [integer, string]
enum: [0, 1, "0", "1"]
relayhost:
type: [integer, string]
default: 0
description: ID of a sender-dependent transport, 0 = none
shared:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: Shared mailbox without a login of its own, opened by group members
quarantine_notification:
type: string
enum:
- never
- hourly
- daily
- weekly
quarantine_category:
type: string
enum:
- reject
- add_header
- all
tagged_mail_handler:
type: string
enum:
- subfolder
- subject
- none
description: Handling of mail to address+tag, see `edit/delimiter_action`
acl:
type: array
description: User ACLs to grant; when sent, all others are off
items:
$ref: "#/components/schemas/UserAclName"
rl_value:
type: [integer, string]
description: Rate limit, messages per `rl_frame` (0 or empty = none)
rl_frame:
type: string
enum:
- s
- m
- h
- d
attribute_hash:
type: string
description: Internal, the hash of the template the values come from
MailboxEdit:
type: object
properties:
active:
type: [integer, string]
enum: [0, 1, 2, "0", "1", "2"]
description: 1 active, 0 inactive, 2 login disabled (mail is accepted)
name:
type: string
description: Full name; empty keeps the current name
quota:
type: [integer, string]
description: Quota in MiB, 0 = unlimited; empty keeps the current quota
password:
type: string
format: password
description: New password (authsource mailcow), checked against the password policy
password2:
type: string
format: password
authsource:
type: string
enum:
- mailcow
- keycloak
- generic-oidc
- ldap
description: An external source only if it is the configured identity provider
pw_recovery_email:
type: string
description: Address for password reset mails (authsource mailcow only)
force_pw_update:
type: [integer, string]
enum: [0, 1, "0", "1"]
force_tfa:
type: [integer, string]
enum: [0, 1, "0", "1"]
sogo_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
protocol_access:
type: array
description: Allowed protocols; when sent it replaces the single `*_access` fields
items:
$ref: "#/components/schemas/ProtocolAccessName"
imap_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
pop3_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
smtp_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
sieve_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
eas_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
dav_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
relayhost:
type: [integer, string]
description: ID of a sender-dependent transport, 0 = none
shared:
type: [integer, string]
enum: [0, 1, "0", "1"]
tags:
type: array
items:
type: string
description: Tags to add; existing tags stay (remove with `delete/mailbox/tag/{mailbox}`)
tagged_mail_handler:
type: string
enum:
- subfolder
- subject
- none
sender_acl:
description: >-
Replaces the internal addresses and @domains the mailbox may send
as; `*` (admins only) allows all, `["default"]` removes all
oneOf:
- type: string
- type: array
items:
type: string
extended_sender_acl:
type: string
description: Replaces the external sender addresses or domains, separated by space, comma or semicolon
attribute_hash:
type: string
description: Internal; cleared when not sent
MailboxTemplateInput:
type: object
properties:
quota:
type: [integer, string]
default: 0
description: Quota in MiB, 0 = unlimited
tags:
type: array
items:
type: string
tagged_mail_handler:
type: string
enum:
- subfolder
- subject
- none
default: none
quarantine_notification:
type: string
enum:
- never
- hourly
- daily
- weekly
default: hourly
quarantine_category:
type: string
enum:
- reject
- add_header
- all
default: reject
rl_value:
type: [integer, string]
description: Rate limit, messages per `rl_frame`
rl_frame:
type: string
enum:
- s
- m
- h
- d
default: s
force_pw_update:
type: [integer, string]
enum: [0, 1, "0", "1"]
force_tfa:
type: [integer, string]
enum: [0, 1, "0", "1"]
sogo_access:
type: [integer, string]
enum: [0, 1, "0", "1"]
active:
type: [integer, string]
enum: [0, 1, 2, "0", "1", "2"]
default: 1
tls_enforce_in:
type: [integer, string]
enum: [0, 1, "0", "1"]
tls_enforce_out:
type: [integer, string]
enum: [0, 1, "0", "1"]
protocol_access:
type: array
items:
$ref: "#/components/schemas/ProtocolAccessName"
description: Allowed protocols (default all)
acl:
type: array
items:
$ref: "#/components/schemas/UserAclName"
description: User ACLs granted to new mailboxes
MailboxTemplate:
type: object
properties:
id:
type: integer
template:
type: string
description: Name
type:
type: string
const: mailbox
attributes:
type: object
description: The settings as in the example; quota in bytes, one `acl_<name>` flag per user ACL
additionalProperties: true
created:
type: string
modified:
type: [string, "null"]
Resource:
type: object
properties:
name:
type: string
description: Address of the resource
kind:
type: string
enum:
- location
- group
- thing
multiple_bookings:
type: integer
description: 0 always free, -1 unlimited but busy when booked, n ≥ 1 at most n bookings
description:
type: string
active:
type: integer
active_int:
type: integer
domain:
type: string
local_part:
type: string
AppPassword:
type: object
properties:
id:
type: integer
name:
type: string
mailbox:
type: string
domain:
type: string
password:
type: string
description: Hash of the app password
created:
type: string
modified:
type: [string, "null"]
imap_access:
type: integer
smtp_access:
type: integer
dav_access:
type: integer
eas_access:
type: integer
pop3_access:
type: integer
sieve_access:
type: integer
active:
type: integer
SieveFilter:
type: object
properties:
active:
type: integer
enum: [0, 1]
id:
type: integer
username:
type: string
description: Mailbox
filter_type:
type: string
enum:
- prefilter
- postfilter
script_data:
type: string
description: The Sieve script
script_desc:
type: string
TimeLimitedAlias:
type: object
properties:
address:
type: string
goto:
type: string
description: Mailbox the alias delivers to
description:
type: string
validity:
type: integer
description: Unix time of expiry (0 when made permanent by an edit)
created:
type: string
modified:
type: [string, "null"]
permanent:
type: integer
enum: [0, 1]
SpamPolicyEntry:
type: object
properties:
object:
type: string
description: Mailbox or domain the entry belongs to
value:
type: string
description: Sender address, domain or pattern
prefid:
type: integer
description: ID for `delete/mailbox-policy`
MailboxRatelimit:
type: object
properties:
value:
type: string
description: Number of messages
frame:
type: string
enum:
- s
- m
- h
- d
description: Per second, minute, hour or day
SpamScore:
type: object
properties:
score:
type: string
description: '"low,high": junk folder from low, rejected from high'
LastLogin:
type: object
properties:
ui:
description: Previous successful UI login, `false` if there is none, `[]` for domain admins
oneOf:
- type: object
properties:
remote:
type: string
description: IP address
time:
type: integer
description: Unix time
- type: boolean
const: false
- type: array
maxItems: 0
sasl:
type: array
items:
type: object
properties:
real_rip:
type: string
description: Client IP; private and internal addresses as "Web/EAS/Internal (address)"
datetime:
type: string
service:
type: string
description: e.g. imap, smtp, pop3, SOGO, SSO, MAILCOWUI
app_password:
type: integer
description: ID of the app password used, 0 = none
app_password_name:
type: [string, "null"]
location:
type: string
description: Country code of public addresses (if known)
MailboxSearchRequest:
type: object
description: DataTables server-side request
properties:
draw:
type: integer
description: Counter, returned unchanged
start:
type: integer
description: Offset of the first row; without it all rows are returned
length:
type: integer
description: Rows per page, -1 = all
search:
type: object
properties:
value:
type: string
description: Searched in all searchable columns (substring)
order:
type: array
items:
type: object
properties:
column:
type: integer
description: Column number (index in `columns`)
dir:
type: string
enum:
- asc
- desc
columns:
type: array
description: Column n of the table is `columns[n]`; needed to search or sort
items:
type: object
properties:
data:
type: [string, integer]
description: >-
Name of the column in the UI; for this column's
`search.value` only a column number works, other values
filter the address
searchable:
type: [boolean, string]
description: true or "true" includes the column in the search
orderable:
type: [boolean, string]
description: true or "true" allows sorting by the column
search:
type: object
properties:
value:
type: string
description: Filter for this column only (substring)
MailboxSearchResult:
type: object
properties:
draw:
type: integer
recordsTotal:
type: integer
recordsFiltered:
type: integer
data:
type: array
items:
$ref: "#/components/schemas/Mailbox"
Alias:
type: object
properties:
in_primary_domain:
type: string
description: Target domain if `domain` is an alias domain, else empty
id:
type: integer
domain:
type: string
description: Domain of the address, a domain or alias domain
public_comment:
type: [string, "null"]
description: Comment shown to the users
private_comment:
type: [string, "null"]
description: Comment for administrators
goto:
type: string
description: >-
Comma-separated destination addresses, or `null@localhost`
(discard), `spam@localhost` (learn as spam), `ham@localhost` (learn
as ham)
address:
type: string
description: Alias address, `@example.org` for a catch-all
is_catch_all:
type: integer
description: 1 = catch-all of the domain
internal:
type: integer
description: 1 = only reachable from its own domain and its alias domains
active:
type: integer
description: 1 = active, 0 = inactive
active_int:
type: integer
description: Same as `active`
sogo_visible:
type: integer
description: 1 = selectable sender in SOGo
sogo_visible_int:
type: integer
description: Same as `sogo_visible`
sender_allowed:
type: integer
description: 1 = the destination mailboxes may send as this alias
group_id:
type: [integer, "null"]
description: >-
Mailbox group whose distribution address this is; such aliases can
only be changed in the group
group_name:
type: [string, "null"]
description: Name of that mailbox group
created:
type: string
description: Creation time, `YYYY-MM-DD hh:mm:ss`
modified:
type: [string, "null"]
description: Time of the last change
BccMap:
type: object
properties:
id:
type: integer
local_dest:
type: string
description: Domain as `@example.org` or the address of a mailbox or alias
bcc_dest:
type: string
description: Address that gets the copies
active:
type: integer
description: 1 = active, 0 = inactive
type:
type: string
enum:
- sender
- rcpt
description: "`sender`: mail sent by `local_dest`; `rcpt`: mail sent to it"
created:
type: string
domain:
type: string
description: Domain of `local_dest`
modified:
type: [string, "null"]
RecipientMap:
type: object
properties:
id:
type: integer
recipient_map_old:
type: string
description: Original recipient, an address or `@domain`
recipient_map_new:
type: string
description: New recipient, an address or `@domain`
active:
type: integer
description: 1 = active, 0 = inactive
created:
type: string
modified:
type: [string, "null"]
TlsPolicyMap:
type: object
properties:
id:
type: integer
dest:
type: string
description: Destination
policy:
type: string
enum:
- none
- may
- encrypt
- dane
- dane-only
- fingerprint
- verify
- secure
parameters:
type: [string, "null"]
description: Space-separated `name=value` attributes, may be empty
active:
type: integer
description: 1 = active, 0 = inactive
created:
type: string
modified:
type: [string, "null"]
Relayhost:
type: object
description: A sender-dependent transport
properties:
id:
type: integer
description: The value domains and mailboxes use as `relayhost`
hostname:
type: string
description: Next hop
username:
type: string
description: SMTP user name, empty without authentication
password:
type: string
description: SMTP password in clear text
active:
type: integer
description: 1 = active, 0 = inactive
password_short:
type: string
description: First three characters of the password and `...`
used_by_domains:
type: string
description: Comma-separated domains that use the transport, may be empty
used_by_mailboxes:
type: string
description: Comma-separated mailboxes that use the transport, may be empty
Transport:
type: object
description: A transport map entry
properties:
id:
type: integer
is_mx_based:
type: integer
description: 1 = `destination` is a regular expression for MX names
destination:
type: string
nexthop:
type: string
username:
type: string
description: SMTP user name, empty without authentication
password:
type: string
description: SMTP password in clear text
active:
type: integer
description: 1 = active, 0 = inactive
password_short:
type: string
description: First three characters of the password and `...`
ForwardingHost:
type: object
properties:
host:
type: string
description: IP address or network
source:
type: string
description: What was added (host name, domain or the address itself)
keep_spam:
type: string
enum:
- "yes"
- "no"
description: "`yes` = the mail of the host is not scanned for spam"
RspamdSettingAttributes:
type: object
properties:
desc:
type: string
description: Short description
content:
type: string
description: Rule content in Rspamd settings syntax
active:
type: [boolean, integer, string]
description: 1 = the rule is handed to Rspamd
default: 0
required:
- desc
- content
RspamdSetting:
type: object
properties:
id:
type: integer
desc:
type: string
description: Short description
content:
type: string
description: Rule content in Rspamd settings syntax
active:
type: integer
enum:
- 0
- 1
RspamdRegexMap:
type: string
description: File name of a global Rspamd regex map
enum:
- global_mime_from_blacklist.map
- global_mime_from_whitelist.map
- global_smtp_from_blacklist.map
- global_smtp_from_whitelist.map
- global_rcpt_blacklist.map
- global_rcpt_whitelist.map
- fishy_tlds.map
- bad_words.map
- bad_words_de.map
- bad_languages.map
- bulk_header.map
- bad_header.map
- monitoring_nolog.map
Preset:
type: object
properties:
name:
type: string
description: File name of the preset without `.yml`
headline:
type: string
description: Title, translated
content:
type: string
description: Rspamd settings rule or Sieve script
GlobalFilters:
type: object
properties:
prefilter:
type: string
description: Sieve script that runs before the filters of the mailboxes
postfilter:
type: string
description: Sieve script that runs after the filters of the mailboxes
MailQueueItem:
type: object
description: One message of `postqueue -j`
properties:
queue_name:
type: string
description: Queue, e.g. `active`, `deferred`, `hold`, `incoming`
queue_id:
type: string
arrival_time:
type: integer
description: Unix time
message_size:
type: integer
description: Size in bytes
forced_expire:
type: boolean
sender:
type: string
recipients:
type: array
description: Recipient addresses, with the reason of the delay in brackets if there is one
items:
type: string
QuarantineItem:
type: object
properties:
id:
type: integer
qid:
type: string
description: Postfix queue ID of the message
subject:
type: string
virus_flag:
type: integer
description: Greater than 0 when Rspamd found a virus (`VIRUS_FOUND`)
score:
type: number
description: Rspamd score
rcpt:
type: string
description: Mailbox the item belongs to
sender:
type: string
action:
type: string
description: Rspamd action, e.g. `reject` or `add header`
created:
type: integer
description: Unix time
notified:
type: integer
description: 1 when the recipient got a notification
QuarantineItemDetails:
type: object
properties:
id:
type: integer
qid:
type: string
description: Postfix queue ID of the message
subject:
type: string
score:
type: number
description: Rspamd score
ip:
type: string
description: IP of the sending server
action:
type: string
description: Rspamd action
symbols:
type: string
description: Rspamd symbols as JSON text
fuzzy_hashes:
type: string
description: Fuzzy hashes as JSON text
sender:
type: string
rcpt:
type: string
description: Mailbox the item belongs to
msg:
type: string
description: The raw message
domain:
type: [string, "null"]
notified:
type: integer
description: 1 when the recipient got a notification
created:
type: string
description: Time of quarantining (`YYYY-MM-DD HH:MM:SS`)
user:
type: string
description: Authenticated sender, `unknown` if none
qhash:
type: string
description: Secret of the release and delete links in the notification mails
Fail2Ban:
type: object
properties:
ban_time:
type: integer
description: Ban time in seconds
ban_time_increment:
type: boolean
description: The ban time grows with every ban of a network
max_ban_time:
type: integer
description: Maximum ban time in seconds
netban_ipv4:
type: integer
description: IPv4 prefix length that is banned
netban_ipv6:
type: integer
description: IPv6 prefix length that is banned
max_attempts:
type: integer
description: Failed logins within `retry_window` that lead to a ban
retry_window:
type: integer
description: Window in seconds for `max_attempts`
banlist_id:
type: string
description: ID of the banlist URL `/f2b-banlist?id=<banlist_id>`
manage_external:
type: integer
description: 1 = netfilter sets no rules, the banlist is for an external firewall
regex:
type: object
description: Regex filters by number
additionalProperties:
type: string
whitelist:
type: string
description: Allowlisted networks and hosts, one per line
blacklist:
type: string
description: Denylisted networks, one per line
perm_bans:
type: array
description: Permanent bans (only present when there are any)
items:
type: object
properties:
network:
type: string
ip:
type: string
active_bans:
type: array
description: Active bans (only present when there are any)
items:
type: object
properties:
queued_for_unban:
type: integer
description: 1 when the ban is about to be lifted
network:
type: string
ip:
type: string
banned_until:
type: string
description: Remaining ban time, e.g. `00h 27m 08s`
Admin:
type: object
description: An administrator account
properties:
username:
type: string
tfa_active:
type: integer
enum: [0, 1]
description: 1 = two-factor authentication is active
tfa_active_int:
type: integer
enum: [0, 1]
description: Same as `tfa_active`
active:
type: integer
enum: [0, 1]
description: 1 = the account can log in
active_int:
type: integer
enum: [0, 1]
description: Same as `active`
created:
type: string
description: Creation time (`YYYY-MM-DD hh:mm:ss`)
attributes:
type: object
properties:
force_tfa:
type: string
enum: ["0", "1"]
description: "\"1\" = two-factor authentication must be set up at the next login"
force_pw_update:
type: string
enum: ["0", "1"]
description: "\"1\" = the password must be changed at the next login"
DomainAdmin:
type: object
description: A domain administrator account
properties:
username:
type: string
tfa_active:
type: integer
enum: [0, 1]
description: 1 = two-factor authentication is active
tfa_active_int:
type: integer
enum: [0, 1]
description: Same as `tfa_active`
active:
type: integer
enum: [0, 1]
description: 1 = the account can log in
active_int:
type: integer
enum: [0, 1]
description: Same as `active`
created:
type: string
description: Creation time (`YYYY-MM-DD hh:mm:ss`)
attributes:
type: object
properties:
force_tfa:
type: string
enum: ["0", "1"]
description: "\"1\" = two-factor authentication must be set up at the next login"
force_pw_update:
type: string
enum: ["0", "1"]
description: "\"1\" = the password must be changed at the next login"
selected_domains:
type: array
description: The domains the account administers
items:
type: string
unselected_domains:
description: All other domains, `""` if there are none
oneOf:
- type: array
items:
type: string
- type: string
const: ""
DomainAdminAcl:
type: string
description: >-
ACL of a domain administrator. New domain administrators get all except
`pushover`, `extend_sender_acl` (sender ACL with external addresses),
`unlimited_quota`, `alias_domains` and `domain_desc`.
enum:
- syncjobs
- quarantine
- login_as
- sogo_access
- app_passwds
- bcc_maps
- pushover
- filters
- ratelimit
- spam_policy
- extend_sender_acl
- unlimited_quota
- protocol_access
- smtp_ip_access
- alias_domains
- mailbox_relayhost
- domain_relayhost
- domain_desc
- alias_external_goto
- mailbox_groups
ApiKey:
type: object
description: An API key
properties:
id:
type: integer
description:
type: string
description: Free text; `API_KEY` or `API_KEY_READ_ONLY` for the service keys
access:
type: string
enum:
- ro
- rw
description: "`ro`: read-only (get routes only), `rw`: read/write"
api_key:
type: string
description: The key value, sent in the `X-API-Key` header
allow_from:
type: array
description: IP addresses and networks the key may be used from
items:
type: string
skip_ip_check:
type: integer
enum: [0, 1]
description: 1 = the key may be used from any address
service:
type: integer
enum: [0, 1]
description: 1 = service key from mailcow.conf, can only be changed there
active:
type: integer
enum: [0, 1]
created:
type: [string, "null"]
modified:
type: [string, "null"]
ApiKeyAttributes:
type: object
description: Attributes of an API key for add and edit
properties:
description:
type: string
description: Free text, at most 255 characters
default: ""
access:
type: string
enum:
- ro
- rw
description: "`ro`: read-only (get routes only), `rw`: read/write. Required for a new key."
allow_from:
description: >-
Allowed IP addresses and CIDR networks, as list or as string
separated by spaces, commas, semicolons or newlines. An edit
replaces the list.
oneOf:
- type: string
- type: array
items:
type: string
skip_ip_check:
type: [integer, string, boolean]
description: 1/true = allow the key from any address
default: 0
active:
type: [integer, string, boolean]
description: 1/true = active
default: 1
OAuth2Client:
type: object
description: An OAuth2 client of the mailcow OAuth2 server
properties:
id:
type: integer
description: ID used by the API
client_id:
type: string
description: OAuth2 client ID
client_secret:
type: string
description: OAuth2 client secret
redirect_uri:
type: string
description: Redirect (callback) URL
grant_types:
type: [string, "null"]
description: Not used
scope:
type: string
description: Always `profile`
user_id:
type: [string, "null"]
description: Not used
SyslogLogEntry:
type: object
description: A log line of a container
properties:
time:
type: string
description: Unix time
program:
type: string
description: Process that wrote the line
priority:
type: string
description: Syslog priority (`info`, `warning`, `err`, ...)
message:
type: string
AcmeLogEntry:
type: object
properties:
time:
type: string
description: Unix time
message:
type: string
ApiLogEntry:
type: object
properties:
time:
type: integer
description: Unix time
uri:
type: string
description: Request URI
method:
type: string
description: HTTP method
remote:
type: string
description: Client address
data:
type: string
description: Form data of the request (`attr`, `items`), secrets replaced by `*`
AutodiscoverLogEntry:
type: object
properties:
time:
type: integer
description: Unix time
ua:
type: string
description: User agent of the client
user:
type: string
description: Requested e-mail address
ip:
type: string
description: Client address
service:
type: string
description: Offered service (`activesync`, `imap`) or an error
CronLogEntry:
type: object
properties:
time:
type: integer
description: Unix time
priority:
type: string
task:
type: string
description: Name of the task
message:
type: string
NetfilterLogEntry:
type: object
properties:
time:
type: integer
description: Unix time
priority:
type: string
description: "`info`, `warn` or `crit` (bans)"
message:
type: string
RatelimitLogEntry:
type: object
properties:
time:
type: integer
description: Unix time
rcpt:
type: string
description: Recipients, comma separated
from:
type: string
description: Envelope sender
user:
type: string
description: Authenticated user
rl_info:
type: string
description: Rate limit that was hit, `name(hash)`
rl_name:
type: string
description: Name of the rate limit (mailbox or domain)
rl_hash:
type: string
description: Hash of the rate limit bucket (see `delete/rlhash`)
qid:
type: string
description: Postfix queue ID
ip:
type: string
description: Client address
message_id:
type: string
header_subject:
type: string
header_from:
type: string
RspamdHistoryEntry:
type: object
description: A message scanned by Rspamd (fields of Rspamd's history)
properties:
unix_time:
type: integer
time_real:
type: number
description: Scan time in seconds
score:
type: number
required_score:
type: number
action:
type: string
description: "`no action`, `greylist`, `add header`, `rewrite subject`, `soft reject` or `reject`"
thresholds:
type: object
additionalProperties:
type: number
ip:
type: string
user:
type: string
description: Authenticated user, `unknown` for incoming mail
sender_smtp:
type: string
sender_mime:
type: string
rcpt_smtp:
type: array
items:
type: string
rcpt_mime:
type: array
items:
type: string
subject:
type: string
message-id:
type: string
size:
type: integer
is_skipped:
type: boolean
symbols:
type: object
description: Matched symbols by name
additionalProperties:
type: object
properties:
name:
type: string
score:
type: number
metric_score:
type: number
description:
type: string
options:
type: array
items:
type: string
additionalProperties: true
RspamdStats:
type: object
description: Statistics of Rspamd's controller (`/stat`)
properties:
version:
type: string
config_id:
type: string
uptime:
type: integer
description: Seconds
read_only:
type: boolean
scanned:
type: integer
learned:
type: integer
actions:
type: object
description: Number of messages per action
additionalProperties:
type: integer
scan_times:
type: array
items:
type: [number, "null"]
spam_count:
type: integer
ham_count:
type: integer
connections:
type: integer
control_connections:
type: integer
total_learns:
type: integer
statfiles:
type: array
description: Bayes statistics
items:
type: object
fuzzy_hashes:
type: object
additionalProperties:
type: integer
additionalProperties: true
SaslLogEntry:
type: object
properties:
service:
type: string
description: "`imap`, `pop3`, `smtp`, `sieve`, `SSO` (SOGo), ..."
app_password:
type: integer
description: ID of the app password used, 0 = the mailbox password
username:
type: string
real_rip:
type: string
description: Client address
datetime:
type: string
description: Time of the last login (`YYYY-MM-DD hh:mm:ss`)
UiLogEntry:
type: object
properties:
id:
type: integer
task:
type: string
description: ID of the request
type:
type: string
description: "`success`, `danger`, `warning` or `info`"
msg:
type: string
description: The message (JSON)
call:
type: string
description: The call that produced it (JSON)
user:
type: string
description: Account (`API` for API keys)
role:
type: string
remote:
type: string
description: Client address
time:
type: integer
description: Unix time
WatchdogLogEntry:
type: object
properties:
time:
type: string
description: Unix time
service:
type: string
description: Checked service
lvl:
type: string
description: Health in percent
hpnow:
type: string
description: Current health points
hptotal:
type: string
description: Maximum health points
hpdiff:
type: string
description: Change since the last check
ContainerStatus:
type: object
properties:
type:
type: string
const: info
container:
type: string
description: Service name
state:
type: string
description: Docker state (`running`, `exited`, `restarting`, ...)
started_at:
type: string
description: Start time (RFC 3339)
image:
type: string
HostStats:
type: object
properties:
cpu:
type: object
properties:
cores:
type: integer
usage:
type: number
description: CPU usage in percent
memory:
type: object
properties:
total:
type: integer
description: Bytes
usage:
type: number
description: Memory usage in percent
swap:
type: array
description: Swap total, used, free (bytes), used percent, swapped in, swapped out (bytes)
items:
type: number
uptime:
type: number
description: Seconds since boot
system_time:
type: string
description: Host time (`DD.MM.YYYY hh:mm:ss`)
architecture:
type: string
PasswordPolicy:
type: object
description: Password policy; the values are strings, `false` if never saved
properties:
length:
type: [string, boolean]
description: Minimum length
chars:
type: [string, boolean]
description: "\"1\": at least one letter"
special_chars:
type: [string, boolean]
description: "\"1\": at least one character that is no letter or digit"
lowerupper:
type: [string, boolean]
description: "\"1\": lowercase and uppercase letters"
numbers:
type: [string, boolean]
description: "\"1\": at least one digit"
MailboxGroupAttributes:
type: object
description: >-
Attributes of a mailbox group. Flags take `1`, `true`, `on` or `yes`
for on, anything else is off. Lists take a JSON array or a string
separated by spaces, commas, semicolons or newlines; entries are
lowercased.
properties:
name:
type: string
description: 1-100 characters, unique in the domain
description:
type: string
description: Max. 255 characters
default: ""
address:
type: string
description: >-
Distribution address in the domain of the group, not used by a
mailbox or alias yet; empty = none. Wins over `local_part`.
local_part:
type: string
description: Local part of the address in the domain of the group; empty = no address
members:
type:
- array
- string
items:
type: string
description: Regular mailboxes; replaces the manual members the caller may access
add_members:
type:
- array
- string
items:
type: string
description: Mailboxes to add
remove_members:
type:
- array
- string
items:
type: string
description: Manual members to remove
send_as:
type:
- array
- string
items:
type: string
description: >-
Replaces the addresses the members may send as: mailbox or alias
addresses or `@domain`; for the group address use `sender_allowed`
sender_allowed:
type:
- boolean
- integer
- string
description: Members may send as the group address
default: 0
sogo_visible:
type:
- boolean
- integer
- string
description: Offer the group address as identity in SOGo (only with `sender_allowed`)
default: 0
internal:
type:
- boolean
- integer
- string
description: Only senders of the domain may write to the group address
default: 0
active:
type:
- boolean
- integer
- string
default: 1
imap_grants:
description: >-
Replaces the mailboxes the members may open as Shared/<mailbox>; the
caller needs access to every owner. `subscribe` subscribes the
folders for every member once, within 15 minutes. JSON text is
accepted too.
type:
- array
- string
items:
type: object
required:
- owner
properties:
owner:
type: string
description: Mailbox to share
rights:
type: string
description: >-
read = lookup, read, write-seen; write = also write,
write-deleted, insert, post, expunge, create; full = also delete
enum:
- read
- write
- full
default: read
subscribe:
type:
- boolean
- integer
- string
default: 0
sogo_grants:
description: >-
Replaces the SOGo folders shared with the members; the caller needs
access to every owner. Pending until the owner has opened SOGo once.
`subscribe` subscribes every member once. JSON text is accepted too.
type:
- array
- string
items:
type: object
required:
- owner
properties:
owner:
type: string
description: Mailbox whose folder is shared
type:
type: string
enum:
- Calendar
- Contacts
default: Calendar
folder:
type: string
description: SOGo folder id (`A-Za-z0-9._-`, max. 100 characters)
default: personal
access:
type: string
enum:
- read
- write
default: read
subscribe:
type:
- boolean
- integer
- string
default: 0
template_id:
type:
- integer
- string
- "null"
description: >-
Admins only: id of a mailbox template applied to the members;
null, empty or 0 = none
priority:
type:
- integer
- string
description: >-
Admins only: -1000000 to 1000000; of several groups with a
template the one with the highest priority wins
default: 0
idp_ref:
type: string
description: >-
Admins only: Identity Provider group id to sync the members from
(max. 255 characters); empty = none
MailboxGroup:
type: object
properties:
id:
type: integer
domain:
type: string
name:
type: string
description:
type: string
address:
type:
- string
- "null"
description: Distribution address, null = none
sender_allowed:
type: integer
enum:
- 0
- 1
sogo_visible:
type: integer
enum:
- 0
- 1
internal:
type: integer
enum:
- 0
- 1
template_id:
type:
- integer
- "null"
template:
type:
- string
- "null"
description: Name of the template
priority:
type: integer
idp_ref:
type:
- string
- "null"
description: Identity Provider group id, set = members are synced
members:
type: array
items:
type: object
properties:
username:
type: string
source:
type: string
description: manual = added in mailcow, idp = added by the identity sync
enum:
- manual
- idp
send_as:
type: array
description: Addresses and `@domain` entries the members may send as
items:
type: string
imap_grants:
type: array
items:
type: object
properties:
owner:
type: string
rights:
type: string
enum:
- read
- write
- full
subscribe:
type: integer
enum:
- 0
- 1
state:
type: string
description: failed = setting the ACL failed, retried later
enum:
- pending
- applied
- failed
last_error:
type:
- string
- "null"
sogo_grants:
type: array
items:
type: object
properties:
owner:
type: string
type:
type: string
enum:
- Calendar
- Contacts
folder:
type: string
access:
type: string
enum:
- read
- write
subscribe:
type: integer
enum:
- 0
- 1
state:
type: string
description: pending (`last_error` folder_missing) until the SOGo folder of the owner exists
enum:
- pending
- applied
- failed
last_error:
type:
- string
- "null"
active:
type: integer
enum:
- 0
- 1
created:
type:
- string
- "null"
modified:
type:
- string
- "null"
can_edit:
type: boolean
description: The caller may change the group (false for read-only API keys)
MailboxGroupMemberships:
type: object
properties:
groups:
type: array
items:
type: object
properties:
id:
type: integer
domain:
type: string
name:
type: string
address:
type:
- string
- "null"
sender_allowed:
type: integer
active:
type: integer
priority:
type: integer
template:
type:
- string
- "null"
source:
type: string
enum:
- manual
- idp
template:
type:
- string
- "null"
description: Effective group template of the mailbox
send_as:
type: array
description: Addresses the mailbox may send as through its active groups
items:
type: string
SyncJobAttributes:
type: object
description: >-
Attributes of a sync job. Flags are cast to integers: `1`, `"1"` and
`true` are on; `0`, `"0"`, `false` and the string `"true"` are off.
Flags not sent on add are off. `host1`, `port1`, `enc1` and `authmech1`
are ignored, the connection comes from `source_id`.
properties:
source_id:
type:
- integer
- string
description: >-
Id of an active sync source the caller may see
(`GET /api/v1/get/syncjob_source/all`)
user1:
type: string
description: Remote username at the source, max. 255 characters
password1:
type: string
format: password
description: >-
Remote password; required unless the source uses XOAUTH2 (ignored
then); empty on edit = keep
mins_interval:
type:
- integer
- string
description: Minutes between runs, 1-43800
subfolder2:
type: string
description: Folder in the local mailbox to sync into, empty = none
default: ""
exclude:
type: string
description: Regular expression of remote folders to skip
default: ""
maxage:
type:
- integer
- string
description: Only sync messages up to this age in days (1-32000), 0 = all
default: 0
maxbytespersecond:
type:
- integer
- string
description: >-
Bandwidth limit in bytes/s (1-125000000), 0 = unlimited; the global
limit of `edit/imapsync_settings` caps it
default: 0
timeout1:
type:
- integer
- string
description: Timeout of the remote connection in seconds (1-32000)
default: 600
timeout2:
type:
- integer
- string
description: Timeout of the local connection in seconds (1-32000)
default: 600
custom_params:
type: array
description: >-
Extra imapsync options allowed by `GET /api/v1/get/syncjob_options`;
replaces the stored list, empty or null = none. Max. 100 options,
values max. 1000 characters, each value is one argument.
items:
$ref: "#/components/schemas/SyncJobCustomParam"
delete2duplicates:
type:
- integer
- string
- boolean
description: Delete duplicates in the local mailbox (--delete2duplicates)
delete1:
type:
- integer
- string
- boolean
description: Delete messages at the source after they were synced (--delete1)
delete2:
type:
- integer
- string
- boolean
description: Delete local messages that are not at the source (--delete2)
automap:
type:
- integer
- string
- boolean
description: Map special folders like "Sent Items" to their local counterparts (--automap)
skipcrossduplicates:
type:
- integer
- string
- boolean
description: Skip duplicates across folders, first come first served (--skipcrossduplicates)
subscribeall:
type:
- integer
- string
- boolean
description: Subscribe all folders (--subscribeall)
dry:
type:
- integer
- string
- boolean
description: Dry run, change nothing (--dry)
active:
type:
- integer
- string
- boolean
description: The job runs; a new job without `active` is inactive
default: 0
SyncJobCustomParam:
type: object
required:
- o
properties:
o:
type: string
description: Option name, case-insensitive, leading dashes are removed
example: folder
v:
type: string
description: Value, empty for flags
default: ""
example: INBOX
SyncJob:
type: object
description: A sync job; the remote password is never returned.
properties:
id:
type: integer
user2:
type: string
description: Local mailbox
user1:
type: string
description: Remote username
source_id:
type: integer
subfolder2:
type: string
exclude:
type: string
maxage:
type: integer
mins_interval:
type: integer
maxbytespersecond:
type: string
description: Bytes/s as text, "0" = unlimited
timeout1:
type: integer
timeout2:
type: integer
custom_params:
type:
- string
- "null"
description: 'JSON text of the option list, e.g. `[{"o":"folder","v":"INBOX"}]`'
custom_params_legacy:
type:
- string
- "null"
description: Free-text options of jobs from before the allowlist, not used by the runner
delete2duplicates:
type: integer
delete1:
type: integer
delete2:
type: integer
automap:
type: integer
skipcrossduplicates:
type: integer
subscribeall:
type: integer
dry:
type: integer
active:
type: integer
regextrans2:
type:
- string
- "null"
description: Legacy column, read-only
authmd51:
type: integer
description: Legacy column, read-only
domain2:
type: string
description: Legacy column, read-only
is_running:
type: integer
last_run:
type:
- string
- "null"
success:
type:
- integer
- "null"
description: Result of the last run (1 = imapsync exited with 0), null = not run yet
exit_status:
type:
- string
- "null"
description: Exit status name of imapsync, e.g. EX_OK
prio:
type: integer
description: Queue priority, higher runs first
created:
type:
- string
- "null"
modified:
type:
- string
- "null"
source_name:
type:
- string
- "null"
source_description:
type:
- string
- "null"
source_host:
type:
- string
- "null"
source_port:
type:
- integer
- "null"
source_enc:
type:
- string
- "null"
source_auth_type:
type:
- string
- "null"
source_created_by:
type:
- string
- "null"
source_scope:
type:
- string
- "null"
source_oauth_flow:
type:
- string
- "null"
source_active:
type:
- integer
- "null"
source_oauth_token_expires:
type:
- integer
- "null"
description: Expiry (Unix time) of the token of a client_credentials source
source_oauth_last_refresh_error:
type:
- string
- "null"
user_token_expires:
type:
- integer
- "null"
description: Expiry (Unix time) of the sign-in token of an authorization_code source
user_token_error:
type:
- string
- "null"
user_token_exists:
type: integer
description: 1 = a sign-in token exists for (source, local mailbox, user1)
log:
type: string
description: Output of the last run; empty with `no_log`
SyncJobSourceAttributes:
type: object
description: >-
Attributes of a sync source; on edit, attributes that are not sent keep
their value.
properties:
name:
type: string
description: 1-100 characters, unique per creator
description:
type: string
description: Max. 255 characters
default: ""
host:
type: string
description: IMAP server, host name or IP address (`host1` is accepted too)
port:
type:
- integer
- string
description: 1-65535 (`port1` is accepted too)
enc:
type: string
description: TLS = STARTTLS (`enc1` is accepted too)
enum:
- TLS
- SSL
- PLAIN
default: TLS
verify_cert:
type:
- integer
- string
- boolean
description: Verify the server certificate; `0`, `"0"`, `false` or empty = no
default: 1
auth_type:
type: string
description: >-
PLAIN, LOGIN and CRAM-MD5 use the password of each job, XOAUTH2 an
OAuth2 token. Users cannot create or edit XOAUTH2 sources, but may
use the ones they see.
enum:
- PLAIN
- LOGIN
- CRAM-MD5
- XOAUTH2
default: PLAIN
active:
type:
- integer
- string
description: 1 = usable for jobs (cast to integer)
default: 1
scope:
type: string
description: >-
Who may use the source: `all` (admins only), `domain` (the
`domains`), `user` (the `users`; none = only the creator). Sources
of users and client_credentials sources are always `user` without
targets. On edit the targets only change when `scope` is sent.
enum:
- all
- domain
- user
default: user
domains:
type: array
description: Domains for scope `domain` (at least one), the caller must manage them
items:
type: string
users:
type: array
description: Mailboxes for scope `user`, the caller must have access to them
items:
type: string
oauth_flow:
type: string
description: >-
XOAUTH2 grant: client_credentials = one token of the source for all
mailboxes of the tenant; authorization_code = every mailbox owner
signs in once in the mailcow UI (redirect URI
`https://<MAILCOW_HOSTNAME>/syncjob-oauth`)
enum:
- client_credentials
- authorization_code
default: client_credentials
oauth_token_endpoint:
type: string
description: XOAUTH2, required; https:// URL
oauth_authorize_endpoint:
type: string
description: XOAUTH2 authorization_code, required; https:// URL
oauth_userinfo_endpoint:
type: string
description: >-
XOAUTH2 authorization_code, optional: identity endpoint used when
the token response has no usable id_token; https:// URL
oauth_client_id:
type: string
description: XOAUTH2, required, max. 500 characters
oauth_client_secret:
type: string
format: password
description: >-
XOAUTH2, required, max. 500 characters; empty on edit = keep. Never
returned.
oauth_scope:
type: string
description: XOAUTH2, required, max. 500 characters
oauth_extra_params:
description: >-
XOAUTH2, optional: extra OAuth2 parameters as JSON object or JSON
text (max. 4000 characters). `prompt`, `access_type`, `login_hint`,
`domain_hint` and `hd` go to the sign-in URL, others to the token
request; standard fields cannot be overridden.
type:
- object
- string
- "null"
additionalProperties:
type:
- string
- number
- boolean
- "null"
SyncJobSource:
type: object
description: A sync source; secrets are never returned.
properties:
id:
type: integer
name:
type: string
description:
type: string
created_by:
type: string
description: Creator; `API` for API keys, empty = handed over to the admins (creator deleted)
scope:
type: string
enum:
- all
- domain
- user
domains:
type: array
items:
type: string
users:
type: array
items:
type: string
host:
type: string
port:
type: integer
enc:
type:
- string
- "null"
host1:
type: string
description: Same as `host`
port1:
type: integer
description: Same as `port`
enc1:
type:
- string
- "null"
description: Same as `enc`
verify_cert:
type: integer
auth_type:
type:
- string
- "null"
active:
type: integer
oauth_flow:
type: string
oauth_token_endpoint:
type:
- string
- "null"
oauth_authorize_endpoint:
type:
- string
- "null"
oauth_userinfo_endpoint:
type:
- string
- "null"
oauth_client_id:
type:
- string
- "null"
oauth_scope:
type:
- string
- "null"
oauth_extra_params:
type:
- string
- "null"
description: JSON text, null for callers who may not edit the source
oauth_token_expires:
type:
- integer
- "null"
description: Expiry (Unix time) of the token of a client_credentials source
oauth_last_refresh_error:
type:
- string
- "null"
oauth_last_refresh_attempt:
type:
- string
- "null"
oauth_redirect_uri:
type: string
description: Only for authorization_code sources, register it at the provider
has_client_secret:
type: boolean
has_access_token:
type: boolean
can_edit:
type: boolean
description: The caller may change the source (false for read-only API keys)
created:
type:
- string
- "null"
modified:
type:
- string
- "null"
SyncJobSettings:
type: object
properties:
max_parallel:
type: integer
description: Sync jobs running at the same time
max_bytes_per_second:
type: integer
description: Bandwidth limit per sync job process in bytes/s, 0 = unlimited
max_kb_per_second:
type: integer
description: The same in KB/s
IdentityProviderAttributes:
type: object
required:
- authsource
description: >-
Configuration of the Identity Provider. Flags marked (boolean) are on
for any non-empty value except `0`/`"0"`/`false`; flags marked (0/1) are
cast to integers (the string `"true"` is 0).
properties:
authsource:
type: string
description: Provider type (case-insensitive)
enum:
- keycloak
- generic-oidc
- ldap
client_id:
type: string
description: Keycloak, generic-oidc
client_secret:
type: string
format: password
description: Keycloak, generic-oidc
redirect_url:
type: string
description: Keycloak, generic-oidc; URL of mailcow the provider redirects to after the login
redirect_url_extra:
type:
- array
- string
items:
type: string
description: Keycloak, generic-oidc; more allowed redirect URLs, only changed when sent
server_url:
type: string
description: Keycloak base URL
realm:
type: string
description: Keycloak realm
version:
type: string
description: Keycloak version
mailpassword_flow:
type:
- integer
- string
- boolean
description: (0/1) Keycloak; check mail client passwords through the Keycloak admin API
default: 0
group_paths:
type: string
description: >-
Keycloak group sync: comma-separated group paths, e.g. `/Sales` or
`/mailcow/*` (all groups below /mailcow); needs the `query-groups`
permission
default: ""
authorize_url:
type: string
description: generic-oidc authorization endpoint
token_url:
type: string
description: generic-oidc token endpoint
userinfo_url:
type: string
description: generic-oidc userinfo endpoint
client_scopes:
type: string
description: generic-oidc scopes
default: openid profile email mailcow_template
host:
type: string
description: LDAP server, several separated by commas (spaces are removed)
default: ""
port:
type:
- integer
- string
description: LDAP port
default: 389
use_ssl:
type:
- boolean
- integer
- string
description: (boolean) LDAP over SSL
default: false
use_tls:
type:
- boolean
- integer
- string
description: (boolean) LDAP StartTLS, ignored with `use_ssl`
default: false
basedn:
type: string
description: LDAP base DN of the user search
binddn:
type: string
description: LDAP bind DN
bindpass:
type: string
format: password
description: LDAP bind password
username_field:
type: string
description: LDAP attribute with the mail address of the user
default: mail
filter:
type: string
description: LDAP filter of the users that may log in
default: ""
attribute_field:
type: string
description: LDAP attribute whose value is matched against `mappers`
default: ""
id_attribute:
type: string
description: >-
LDAP attribute with a stable user id; empty = objectGUID, entryUUID,
nsUniqueId or ipaUniqueID, else the DN
default: ""
disabled_filter:
type: string
description: >-
LDAP filter of disabled users (Active Directory accounts with
ACCOUNTDISABLE are always disabled)
default: ""
group_basedn:
type: string
description: LDAP base DN of the group search, empty = `basedn`
default: ""
group_filter:
type: string
description: LDAP filter of the synced groups, required for the group sync
default: ""
group_name_attribute:
type: string
default: cn
group_member_mode:
type: string
description: >-
LDAP source of the memberships: memberOf of the users, member
attribute of the groups, or Active Directory incl. nested groups
enum:
- memberof
- member
- ad_chain
default: memberof
group_member_attribute:
type: string
description: LDAP member attribute for `group_member_mode` member
default: member
ignore_ssl_error:
type:
- boolean
- integer
- string
description: (boolean) Do not verify TLS certificates
default: false
login_provisioning:
type:
- boolean
- integer
- string
description: (boolean) Create mailboxes at their first login
default: false
periodic_sync:
type:
- integer
- string
- boolean
description: (0/1) Keycloak, LDAP; update mailboxes from the provider every `sync_interval`
default: 0
import_users:
type:
- integer
- string
- boolean
description: (0/1) Keycloak, LDAP; create mailboxes for new users of the provider
default: 0
sync_interval:
type:
- integer
- string
description: Keycloak, LDAP; minutes between sync runs (at least 1)
default: 15
offboarding:
type:
- integer
- string
- boolean
description: >-
(0/1) Keycloak, LDAP; disable the login (mail still arrives) of users
disabled at the provider or missing in two complete runs; the sync
enables only mailboxes it disabled
default: 0
offboarding_limit:
type:
- integer
- string
description: >-
Keycloak, LDAP; runs that would disable more mailboxes or remove
more group memberships than this share in percent (0-100, at least
5 mailboxes) are blocked
default: 10
group_sync:
type:
- integer
- string
- boolean
description: >-
(0/1) Keycloak, LDAP; sync the members of provider groups to mailbox
groups (members added in mailcow stay)
default: 0
group_autocreate:
type:
- integer
- string
- boolean
description: >-
(0/1) Keycloak, LDAP; create a mailbox group for every provider
group without one
default: 0
group_default_domain:
type: string
description: Keycloak, LDAP; domain of new groups whose mail is not in a mailcow domain
default: ""
default_template:
type: string
description: >-
Mailbox template for new mailboxes without a matching mapping (not
used for updates); only changed when sent
mappers:
type: array
items:
type: string
description: >-
Attribute values, each mapped to the template at the same position
in `templates`; only changed when both lists are sent, pairs with an
empty value are dropped
templates:
type: array
items:
type: string
description: Mailbox templates for `mappers`
IdentityProviderSettings:
type: object
description: >-
Stored settings (see `IdentityProviderAttributes`), mostly as strings.
Secrets are `*` for read-only API keys.
properties:
authsource:
type: string
client_secret:
type: string
bindpass:
type: string
access_token:
type: string
description: Cached admin API token of Keycloak
redirect_url_extra:
type: array
items:
type: string
mappers:
type: array
items:
type: string
templates:
type: array
items:
type: string
use_ssl:
type: boolean
use_tls:
type: boolean
ignore_ssl_error:
type: boolean
login_provisioning:
type:
- boolean
- integer
additionalProperties:
type: string
IdentitySyncStatus:
type: object
properties:
provider:
type: string
description: Configured provider, empty = none
can_sync:
type: boolean
description: The provider can be synced (Keycloak, LDAP)
sync_enabled:
type: boolean
description: Scheduled runs are on (periodic sync, import, offboarding or group sync)
counts:
type: object
description: Mailboxes of the provider (no resources)
properties:
accounts:
type: integer
linked:
type: integer
description: Linked to a user of the provider
idp_disabled:
type: integer
description: Login disabled by the sync
missing:
type: integer
description: Not found at the provider by the last runs
runs:
type: array
description: The last 10 runs, newest first
items:
$ref: "#/components/schemas/IdentitySyncRun"
IdentitySyncRun:
type: object
properties:
id:
type: integer
provider:
type: string
mode:
type: string
enum:
- run
- preview
- force
status:
type: string
enum:
- pending
- running
- ok
- blocked
- error
requested_by:
type: string
description: Who requested the run, empty for scheduled runs
created:
type: string
started:
type:
- string
- "null"
finished:
type:
- string
- "null"
summary:
type:
- object
- "null"
description: >-
Result, null while pending: `counts` per kind of change, `details`
(up to 50 entries per list), `blocked`, `errors` (up to 50), `mode`;
failed runs only `error` and `mode`
properties:
counts:
type: object
additionalProperties:
type: integer
details:
type: object
additionalProperties:
type: array
items:
type: string
blocked:
type: boolean
errors:
type: array
items:
type: string
error:
type: string
mode:
type: string
IdentityLink:
type: object
properties:
provider:
type: string
external_id:
type:
- string
- "null"
description: User id at the provider
idp_disabled:
type: integer
description: 1 = login disabled by the identity sync
missing_since:
type:
- string
- "null"
description: Since when the sync does not find the user at the provider
responses:
Unauthorized:
description: >-
The API key is unknown or inactive (`authentication failed`), or the
request comes from an address the key does not allow
(`api access denied for ip <address>`)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
type: error
msg: authentication failed
Forbidden:
description: The API key is read-only
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
type: error
msg: API read/write access denied
WriteResult:
description: >-
The messages of the call; `{"type": "success", "msg": "Task completed"}`
or `{"type": "error", "msg": "Cannot ... item"}` if it produced none.
Check `type`: the status is 200 for failures too.
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/Messages"
- $ref: "#/components/schemas/TaskResult"
examples:
messages:
summary: Messages of the call
value:
- type: success
log:
- mailbox
- add
- alias
- address: alias@example.org
goto: user@example.org
msg:
- alias_added
- alias@example.org
failed:
summary: Failed without a message
value:
type: error
msg: Cannot add item
AcmeLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/AcmeLogEntry"
example:
- time: "1794308452"
message: mail.example.org - Certificates were successfully validated, no changes or renewals required, sleeping for another day.
ApiLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ApiLogEntry"
example:
- time: 1794334338
uri: /api/v1/edit/domain-admin
method: POST
remote: 192.0.2.10
data: "attr='{\"active\":\"1\",\"password\":\"*\",\"password2\":\"*\"}', items='[\"domainadmin1\"]'"
- time: 1794334330
uri: /api/v1/get/status/version
method: GET
remote: 192.0.2.10
data: ""
AutodiscoverLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/AutodiscoverLogEntry"
example:
- time: 1794311051
ua: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.17928; Pro)
user: john.doe@example.org
ip: 198.51.100.7
service: activesync
CronLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/CronLogEntry"
example:
- time: 1794096901
priority: warning
task: Group Shares
message: "group_imap_grant_failed: info@example.org"
DovecotLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SyslogLogEntry"
example:
- time: "1794334332"
program: dovecot
priority: info
message: "imap-login: Login: user=<john.doe@example.org>, method=PLAIN, rip=198.51.100.7, lip=172.22.1.250, mpid=310, TLS, session=<c0kD4l8L2N7GZGMH>"
NetfilterLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/NetfilterLogEntry"
example:
- time: 1794334242
priority: crit
message: Banning 203.0.113.5/32 for 30 minutes
- time: 1794334242
priority: warn
message: "203.0.113.5 matched rule id 3 (warning: unknown[203.0.113.5]: SASL LOGIN authentication failed: ...)"
PostfixLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SyslogLogEntry"
example:
- time: "1794334301"
program: postfix/smtpd
priority: info
message: "connect from mail.example.com[198.51.100.20]"
RatelimitLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/RatelimitLogEntry"
example:
- time: 1794334001
rcpt: jane@example.com
from: john.doe@example.org
user: john.doe@example.org
rl_info: john.doe@example.org(RLsdz3tuabozgd4oacbdh8kc78)
rl_name: john.doe@example.org
rl_hash: RLsdz3tuabozgd4oacbdh8kc78
qid: E3CF91500458
ip: 172.22.1.248
message_id: 6a-5d892500-7-240abd80@example.org
header_subject: Newsletter
header_from: "\"John Doe\" <john.doe@example.org>"
RspamdHistory:
description: The scanned messages, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/RspamdHistoryEntry"
example:
- unix_time: 1794333685
time_real: 0.510136
score: -1.229459
required_score: 15
action: no action
thresholds:
reject: 15
add header: 8
greylist: 7
ip: 198.51.100.20
user: unknown
sender_smtp: jane@example.com
sender_mime: jane@example.com
rcpt_smtp:
- john.doe@example.org
rcpt_mime:
- john.doe@example.org
subject: Meeting tomorrow
message-id: 20261110190100.428319@mail.example.com
size: 1015
is_skipped: false
symbols:
DMARC_POLICY_ALLOW:
name: DMARC_POLICY_ALLOW
score: -0.5
metric_score: -0.5
description: DMARC permit policy
options:
- example.com
- none
SaslLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SaslLogEntry"
example:
- service: imap
app_password: 0
username: john.doe@example.org
real_rip: 198.51.100.7
datetime: "2026-11-10 19:07:01"
SogoLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SyslogLogEntry"
example:
- time: "1794334303"
program: sogod
priority: notice
message: "[52]: 198.51.100.7 \"GET /SOGo/so/john.doe@example.org/Mail/view HTTP/1.1\" 200 2578/0 0.002 - - 0 - 12"
UiLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/UiLogEntry"
example:
- id: 1819
task: 97D254
type: success
msg: "[\"domain_admin_modified\",\"domainadmin1\"]"
call: "[\"domain_admin\",\"edit\",{\"username\":[\"domainadmin1\"],\"active\":\"1\"}]"
user: API
role: admin
remote: 192.0.2.10
time: 1794319670
WatchdogLogs:
description: The log entries, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/WatchdogLogEntry"
example:
- time: "1794334334"
service: Dovecot
lvl: "100"
hpnow: "12"
hptotal: "12"
hpdiff: "0"
parameters:
MailboxTagsQuery:
name: tags
in: query
required: false
description: "Comma-separated tags: only mailboxes with a tag containing one of them"
schema:
type: string
example: sales,support
examples:
MailboxDetails:
summary: A mailbox
value:
username: john.doe@example.org
active: 1
active_int: 1
domain: example.org
name: John Doe
local_part: john.doe
quota: 3221225472
messages: 1207
attributes:
force_pw_update: "0"
force_tfa: "0"
tls_enforce_in: "0"
tls_enforce_out: "0"
sogo_access: "1"
imap_access: "1"
pop3_access: "0"
smtp_access: "1"
sieve_access: "1"
eas_access: "1"
dav_access: "1"
relayhost: "0"
shared: "0"
passwd_update: "2026-11-03 09:37:37"
mailbox_format: "maildir:"
quarantine_notification: hourly
quarantine_category: reject
attribute_hash: ""
recovery_email: ""
custom_attributes:
department: Sales
quota_used: 418219315
percent_in_use: 13
created: "2026-11-03 09:37:37"
modified: "2026-11-06 20:20:46"
authsource: mailcow
percent_class: success
last_imap_login: 1794052021
last_smtp_login: 1793788402
last_pop3_login: 0
last_sso_login: 1794005152
last_sogo_login: 1794005160
max_new_quota: 10737418240
spam_aliases: 1
pushover_active: 0
rl:
value: "100"
frame: h
rl_scope: mailbox
is_relayed: 0
sender_acl:
- sales@example.org
tags:
- sales
MailboxList:
summary: Mailboxes
value:
- username: john.doe@example.org
active: 1
active_int: 1
domain: example.org
name: John Doe
local_part: john.doe
quota: 3221225472
messages: 1207
attributes:
force_pw_update: "0"
force_tfa: "0"
tls_enforce_in: "0"
tls_enforce_out: "0"
sogo_access: "1"
imap_access: "1"
pop3_access: "0"
smtp_access: "1"
sieve_access: "1"
eas_access: "1"
dav_access: "1"
relayhost: "0"
shared: "0"
passwd_update: "2026-11-03 09:37:37"
mailbox_format: "maildir:"
quarantine_notification: hourly
quarantine_category: reject
attribute_hash: ""
custom_attributes: []
quota_used: 418219315
percent_in_use: 13
created: "2026-11-03 09:37:37"
modified: "2026-11-06 20:20:46"
authsource: mailcow
percent_class: success
last_imap_login: 1794052021
last_smtp_login: 1793788402
last_pop3_login: 0
last_sso_login: 0
last_sogo_login: 1794005160
max_new_quota: 10737418240
spam_aliases: 0
pushover_active: 0
rl: false
rl_scope: domain
is_relayed: 0
sender_acl: []
MailboxSearchPage:
summary: One page of mailboxes
value:
draw: 1
recordsTotal: 1
recordsFiltered: 1
data:
- username: john.doe@example.org
active: 1
active_int: 1
domain: example.org
name: John Doe
local_part: john.doe
quota: 3221225472
messages: 1207
attributes:
force_pw_update: "0"
force_tfa: "0"
tls_enforce_in: "0"
tls_enforce_out: "0"
sogo_access: "1"
imap_access: "1"
pop3_access: "0"
smtp_access: "1"
sieve_access: "1"
eas_access: "1"
dav_access: "1"
relayhost: "0"
shared: "0"
passwd_update: "2026-11-03 09:37:37"
mailbox_format: "maildir:"
quarantine_notification: hourly
quarantine_category: reject
attribute_hash: ""
custom_attributes: []
quota_used: 418219315
percent_in_use: 13
created: "2026-11-03 09:37:37"
modified: "2026-11-06 20:20:46"
authsource: mailcow
percent_class: success
last_imap_login: 1794052021
last_smtp_login: 1793788402
last_pop3_login: 0
last_sso_login: 0
last_sogo_login: 1794005160
max_new_quota: 10737418240
spam_aliases: 0
pushover_active: 0
rl: false
rl_scope: domain
is_relayed: 0
sender_acl: []
tags:
- sales
security:
- ApiKeyAuth: []
paths:
/api/v1/add/alias:
post:
tags:
- Aliases
summary: Create aliases
operationId: addAlias
description: >-
Creates an alias for every address in `address`, all with the same
destinations; domain administrators for their domains. Flags not sent
are 0: send `active`, `sogo_visible` and `sender_allowed` as 1 to get
an alias like the UI creates it.
Messages: `alias_added`; errors `is_alias_or_mailbox`, `goto_invalid`,
`external_goto_denied`, `max_alias_exceeded`.
requestBody:
content:
application/json:
schema:
type: object
properties:
address:
type: string
description: >-
Alias addresses of mailcow domains or alias domains,
separated by spaces, commas, semicolons or line breaks;
`@example.org` is a catch-all
goto:
type: string
description: >-
Destination addresses, separated by spaces, commas,
semicolons or line breaks; required unless a `goto_*` flag
is 1
goto_null:
type: [boolean, integer, string]
description: 1 = discard the mail silently; wins over `goto_spam` and `goto_ham`
default: 0
goto_spam:
type: [boolean, integer, string]
description: 1 = learn the mail as spam; wins over `goto_ham`
default: 0
goto_ham:
type: [boolean, integer, string]
description: 1 = learn the mail as ham
default: 0
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
default: 0
sogo_visible:
type: [boolean, integer, string]
description: 1 = selectable sender in SOGo (aliases with a local mailbox as destination)
default: 0
internal:
type: [boolean, integer, string]
description: 1 = only reachable from its own domain and its alias domains
default: 0
sender_allowed:
type: [boolean, integer, string]
description: 1 = the destination mailboxes may send as this alias
default: 0
public_comment:
type: string
description: Comment shown to the users
maxLength: 160
private_comment:
type: string
description: Comment for administrators
maxLength: 160
required:
- address
example:
address: sales@example.org
goto: anna@example.org,ben@example.org
active: "1"
sogo_visible: "1"
sender_allowed: "1"
internal: "0"
public_comment: Sales team
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/time_limited_alias:
post:
tags:
- Mailbox user settings
summary: Create a time-limited alias
operationId: addTimeLimitedAlias
description: >-
Creates a random alias that delivers to the mailbox until it expires.
Needs the user ACL `spam_alias`. `domain` must be the domain of the
mailbox or one of its alias domains.
Messages: `mailbox_modified`; errors `domain_invalid`,
`validity_missing`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- domain
properties:
username:
type: string
description: Mailbox the alias delivers to (required for API keys)
domain:
type: string
description: Domain of the alias
description:
type: string
default: ""
description: Note for the alias
validity:
type: [integer, string]
minimum: 1
maximum: 87600
default: 8760
description: Hours until the alias expires
permanent:
type: [boolean, integer, string]
default: false
description: true keeps the alias after it expired
example:
username: john.doe@example.org
domain: example.org
description: Online shop registration
validity: 720
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/api-key:
post:
summary: Create API key
description: >-
Creates an API key with a random value; read the value with
`get/api-key/all`. Without `skip_ip_check`, `allow_from` is required.
Messages: `api_key_added`; errors `api_key_access_invalid`,
`api_key_network_invalid`, `ip_list_empty`.
operationId: addApiKey
tags:
- API Keys
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/ApiKeyAttributes"
- required:
- access
example:
description: provisioning
access: rw
allow_from: "192.0.2.10, 2001:db8::/64"
skip_ip_check: 0
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/app-passwd:
post:
tags:
- App Passwords
summary: Create an app password
operationId: addAppPassword
description: >-
Adds an app password to a mailbox, valid only for the listed protocols.
Needs the user ACL `app_passwds`.
Messages: `app_passwd_added`; errors `password_complexity`,
`password_mismatch`, `app_name_empty`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- app_name
- app_passwd
- app_passwd2
properties:
username:
type: string
description: Mailbox the app password belongs to (required for API keys)
app_name:
type: string
description: Name of the app password
app_passwd:
type: string
format: password
description: The password, checked against the password policy
app_passwd2:
type: string
format: password
description: The password again
protocols:
description: Protocols the password is valid for; not listed = not allowed
type: array
items:
type: string
enum:
- imap_access
- smtp_access
- pop3_access
- sieve_access
- dav_access
- eas_access
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: 1 active, 0 inactive
example:
username: john.doe@example.org
app_name: Thunderbird
app_passwd: eiQu4ahz8iePh
app_passwd2: eiQu4ahz8iePh
protocols:
- imap_access
- smtp_access
- sieve_access
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/bcc:
post:
tags:
- Address Rewriting
summary: Create a BCC map
operationId: addBccMap
description: >-
Sends a hidden copy of the mail of a domain or address to `bcc_dest`.
Domain administrators need the BCC maps ACL. Undeliverable copies are
not reported to the local destination.
Messages: `bcc_saved`; errors `bcc_must_be_email`, `bcc_exists`.
requestBody:
content:
application/json:
schema:
type: object
properties:
local_dest:
type: string
description: A mailcow domain or the address of a mailbox or alias
bcc_dest:
type: string
description: One e-mail address that gets the copies (use an alias for several)
type:
type: string
enum:
- sender
- rcpt
description: >-
`sender`: copy the mail sent by `local_dest`; `rcpt`: copy
the mail sent to it
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
default: 0
required:
- local_dest
- bcc_dest
- type
example:
local_dest: example.org
bcc_dest: archive@example.com
type: rcpt
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/dkim:
post:
summary: Generate DKIM keys
description: >-
Generates an RSA DKIM key for each domain or alias domain; existing
keys are kept.
Messages: `dkim_added`; error `dkim_domain_or_sel_invalid`.
operationId: addDkimKey
tags:
- DKIM
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- domains
- key_size
properties:
domains:
type: string
description: >-
Domain names, separated by spaces, commas, semicolons or
line breaks
dkim_selector:
type: string
default: dkim
description: Selector (letters, digits, `-`, `_`, `.`)
key_size:
type: [integer, string]
description: RSA key size in bits
example:
domains: example.org, example.net
dkim_selector: dkim
key_size: 2048
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/dkim_duplicate:
post:
summary: Copy a DKIM key to other domains
description: >-
Copies the DKIM key and selector of `from_domain` to the `to_domain`
domains, replacing their keys. Target names are not checked.
Messages: `dkim_duplicated`; error `dkim_domain_or_sel_invalid`.
operationId: duplicateDkimKey
tags:
- DKIM
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- from_domain
- to_domain
properties:
from_domain:
type: string
description: Domain whose key is copied
to_domain:
description: Domain name or list of domain names that get the key
oneOf:
- type: string
- type: array
items:
type: string
example:
from_domain: example.org
to_domain:
- example.net
- example.com
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/domain:
post:
summary: Add a domain
description: >-
Adds a domain. Quotas are in MiB. Fields not sent come from the domain
template in `template` (default: `Default`). Also sets the rate limit
and creates a DKIM key. SOGo sees the new domain only after a restart
(`restart_sogo`).
Messages: `domain_added`, `dkim_added`, `rl_saved`; errors
`domain_invalid`, `domain_exists`, `maxquota_empty`.
operationId: addDomain
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- domain
properties:
domain:
type: string
description: Domain name (stored lowercase, IDN as punycode)
description:
type: string
description: Description, default the domain name
template:
type: [integer, string]
description: ID of the domain template for fields not sent
aliases:
type: [integer, string]
description: Max. number of aliases
mailboxes:
type: [integer, string]
description: Max. number of mailboxes
defquota:
type: [integer, string]
description: Default quota of new mailboxes in MiB, must not be 0
maxquota:
type: [integer, string]
description: Max. quota per mailbox in MiB, must not be 0
quota:
type: [integer, string]
description: Quota of the whole domain in MiB
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Domain active
gal:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Global address list in SOGo
backupmx:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Relay this domain (backup MX)
relay_all_recipients:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: >-
Relay all recipients, not only those with a mailbox; 1 sets
`backupmx`
relay_unknown_only:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: >-
Relay only recipients without a local mailbox; 1 sets
`backupmx` and `relay_all_recipients`
tags:
type: array
items:
type: string
description: >-
Tags of the domain, at most 25 (more are dropped with
`tag_limit_exceeded`)
rl_value:
type: [integer, string]
description: Rate limit, messages per `rl_frame`; empty or 0 = none
rl_frame:
type: string
enum: [s, m, h, d]
description: Rate limit time frame
dkim_selector:
type: string
description: Selector of the DKIM key that is created
key_size:
type: [integer, string]
description: RSA size of the new DKIM key in bits; empty or 0 = no key
restart_sogo:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: Restart SOGo afterwards
example:
domain: example.org
description: Example Org
aliases: 400
mailboxes: 10
defquota: 3072
maxquota: 10240
quota: 10240
active: 1
gal: 1
backupmx: 0
relay_all_recipients: 0
relay_unknown_only: 0
tags:
- customer
rl_value: 100
rl_frame: h
dkim_selector: dkim
key_size: 2048
restart_sogo: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/domain-admin:
post:
summary: Create domain administrator
description: >-
Creates a domain administrator for the given domains with the default
ACLs. The username is stored in lowercase and must not be in use by a
mailbox or administrator. Without `active: 1` the account is disabled.
Unknown domains are skipped; if none exists, nothing is created, but
`domain_admin_added` is reported anyway.
Messages: `domain_admin_added`; errors `domain_invalid`,
`object_exists`, `password_complexity`, `password_mismatch`.
operationId: addDomainAdmin
tags:
- Domain admin
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
username:
type: string
description: Username (letters, digits, `_`, `.`, `-`; stored in lowercase)
password:
type: string
description: Password, must match the password policy
password2:
type: string
description: The password again
domains:
description: Domain or list of domains the account administers
oneOf:
- type: string
- type: array
items:
type: string
active:
type: [integer, string, boolean]
description: 1 = the account can log in, 0 = disabled
default: 0
required:
- username
- password
- password2
- domains
example:
username: domainadmin1
password: "Rand0m-Passw0rd!"
password2: "Rand0m-Passw0rd!"
domains:
- example.org
- example.com
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/sso/domain-admin:
post:
summary: Issue domain administrator login token
description: >-
Issues a one-time login token for an active domain administrator, valid
for 30 seconds. Opening `/domainadmin/mailbox?sso_token=<token>` on the
mailcow host logs in without password or two-factor authentication.
Messages: error `object_doesnt_exist`.
operationId: issueDomainAdminSsoToken
tags:
- Single Sign-On
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
username:
type: string
description: Username of the domain administrator
required:
- username
example:
username: domainadmin1
responses:
"200":
description: The token, or the error messages
content:
application/json:
schema:
oneOf:
- type: object
properties:
token:
type: string
description: Login token (five groups of six hex digits)
required:
- token
- $ref: "#/components/schemas/Messages"
example:
token: 591F6D-5C3DD2-7455CD-DAF1C1-AA4FCC
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/da-acl:
post:
summary: Edit domain administrator ACLs
description: >-
Grants the ACLs in `da_acl` and revokes all others; an empty or missing
`da_acl` revokes all.
Messages: `acl_saved`; error `Cannot determine current ACL`.
operationId: editDomainAdminAcl
tags:
- Domain admin
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
items:
description: Username of the domain administrator, or a list of usernames
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
properties:
da_acl:
description: The ACLs to grant (a single name or a list)
oneOf:
- $ref: "#/components/schemas/DomainAdminAcl"
- type: array
items:
$ref: "#/components/schemas/DomainAdminAcl"
required:
- items
- attr
example:
items:
- domainadmin1
attr:
da_acl:
- syncjobs
- quarantine
- login_as
- sogo_access
- app_passwds
- bcc_maps
- filters
- ratelimit
- spam_policy
- protocol_access
- smtp_ip_access
- mailbox_relayhost
- domain_relayhost
- alias_external_goto
- mailbox_groups
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/domain-admin:
post:
summary: Edit domain administrators
description: >-
Changes domain administrators. Fields not sent keep their value, but
`force_tfa` and `force_pw_update` are reset to 0. `domains` replaces
the domain list, empty keeps it; an empty `password` keeps the
password. FIDO2 keys are not moved on rename. A password error ends
the call after the domains were saved.
Messages: `domain_admin_modified`; errors `domain_invalid`,
`username_invalid`, `password_mismatch`, `password_complexity`.
operationId: editDomainAdmin
tags:
- Domain admin
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
items:
description: Username of the domain administrator, or a list of usernames
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
properties:
active:
type: [integer, string, boolean]
description: 1 = active, 0 = disabled
username_new:
type: string
description: New username (letters, digits, `_`, `.`, `-`)
domains:
description: The domains the account administers from now on
oneOf:
- type: string
- type: array
items:
type: string
password:
type: string
description: New password; empty or missing keeps the password
password2:
type: string
description: The new password again
force_tfa:
type: [integer, string, boolean]
description: 1 = two-factor authentication must be set up at the next login
default: 0
force_pw_update:
type: [integer, string, boolean]
description: 1 = the password must be changed at the next login
default: 0
disable_tfa:
type: [integer, string, boolean]
description: Present (any value) = turn off two-factor authentication
required:
- items
- attr
example:
items:
- domainadmin1
attr:
active: 1
domains:
- example.org
password: "N3w-Passw0rd!"
password2: "N3w-Passw0rd!"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/domain-policy:
post:
summary: Add a sender to a domain allow or deny list
description: >-
Adds a sender to the allow list (`wl`) or deny list (`bl`) of a domain;
a sender can be on only one list. Needs the ACL `spam_policy`.
Messages: `domain_modified`; errors `policy_list_from_invalid`,
`policy_list_from_exists`.
operationId: addDomainPolicy
tags:
- Domain antispam policies
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- domain
- object_list
- object_from
properties:
domain:
type: string
description: Domain the entry belongs to
object_list:
type: string
enum: [wl, bl]
description: "`wl` allow list (whitelist), `bl` deny list (blacklist)"
object_from:
type: string
description: >-
Sender address or pattern with `*` as wildcard; letters,
digits and `@ _ . - *`
example:
domain: example.org
object_list: wl
object_from: "*@partner.example.com"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/fwdhost:
post:
tags:
- Forwarding Hosts
summary: Add forwarding hosts
operationId: addForwardingHost
description: >-
Adds hosts whose mail is accepted unconditionally: no DNSBL checks, no
greylisting, no spam rejects. A name becomes one entry per address of
its SPF record, else its MX hosts, else A/AAAA.
Messages: `forwarding_host_added`; errors `invalid_host`.
requestBody:
content:
application/json:
schema:
type: object
properties:
hostname:
type: string
description: >-
IPv4 or IPv6 address, network in CIDR notation, host name
or domain name
filter_spam:
type: [boolean, integer, string]
description: 1 = scan the mail for spam (junk folder, never rejected); else not
default: 0
required:
- hostname
example:
hostname: relay.example.com
filter_spam: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/fwdhost:
post:
tags:
- Forwarding Hosts
summary: Update forwarding hosts
operationId: editForwardingHost
description: >-
Turns the spam filter of forwarding hosts on or off; without
`keep_spam` it is turned on.
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: >-
Hosts as get/fwdhost lists them (`host`), a single value or
a list
oneOf:
- type: array
items:
type: string
- type: string
attr:
type: object
properties:
keep_spam:
type: [boolean, integer, string]
description: 1 = do not scan the mail for spam; else scan it
required:
- items
- attr
example:
items:
- 192.0.2.25
- "2001:db8::25"
attr:
keep_spam: "0"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/mailbox:
post:
tags:
- Mailboxes
summary: Create a mailbox
operationId: addMailbox
description: >-
Creates a mailbox, also for domain admins. Quotas are in MiB. Fields
not sent come from the mailbox template in `template` (default:
`Default`). Quota 0 (unlimited) needs the `unlimited_quota` ACL.
Messages: `mailbox_added`; errors `object_exists`, `domain_not_found`,
`password_complexity`, `max_mailbox_exceeded`,
`mailbox_quota_exceeded`.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MailboxAdd"
example:
local_part: john.doe
domain: example.org
name: John Doe
password: Moo2Shoh5aiXu
password2: Moo2Shoh5aiXu
quota: 3072
active: 1
force_pw_update: 1
tags:
- sales
acl:
- spam_alias
- spam_score
- delimiter_action
- app_passwds
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/mailbox-group:
post:
summary: Create mailbox group
description: >-
Creates a mailbox group. With an address it is also a distribution list
to its members; the address counts against the alias limit of the
domain. Domain admins need the `mailbox_groups` ACL. Follow-up steps
that fail answer a warning and are retried later.
Messages: `group_added`; warnings `group_template_failed`,
`group_imap_grant_failed`; errors `object_exists`,
`group_address_invalid`, `max_alias_exceeded`, `group_member_invalid`.
operationId: addMailboxGroup
tags:
- Groups
requestBody:
content:
application/json:
schema:
allOf:
- type: object
required:
- domain
- name
properties:
domain:
type: string
description: Domain of the group (no alias domain), case-insensitive
- $ref: "#/components/schemas/MailboxGroupAttributes"
example:
domain: example.org
name: Sales
description: Sales team
local_part: sales
members:
- alice@example.org
- bob@example.org
send_as:
- orders@example.org
sender_allowed: 1
imap_grants:
- owner: shared@example.org
rights: write
subscribe: 1
template_id: 3
priority: 10
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/oauth2-client:
post:
summary: Create OAuth2 client
description: >-
Creates an OAuth2 client with random ID and secret; read them with
`get/oauth2-client/all`. The redirect URI is not validated.
Messages: `Added client access`.
operationId: addOAuth2Client
tags:
- oAuth Clients
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
redirect_uri:
type: string
description: Redirect (callback) URL of the client application
required:
- redirect_uri
example:
redirect_uri: https://app.example.org/oauth/callback
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/recipient_map:
post:
tags:
- Address Rewriting
summary: Create a recipient map
operationId: addRecipientMap
description: >-
Rewrites the recipient before delivery: mail to `recipient_map_old`
goes to `recipient_map_new`.
Messages: `recipient_map_entry_saved`; errors
`invalid_recipient_map_old`, `invalid_recipient_map_new`,
`recipient_map_entry_exists`.
requestBody:
content:
application/json:
schema:
type: object
properties:
recipient_map_old:
type: string
description: Original recipient, an e-mail address or a domain (leading `@` optional)
recipient_map_new:
type: string
description: New recipient, an e-mail address or a domain
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
default: 0
required:
- recipient_map_old
- recipient_map_new
example:
recipient_map_old: jane.doe@example.org
recipient_map_new: jane.smith@example.org
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/relayhost:
post:
tags:
- Routing
summary: Create a sender-dependent transport
operationId: addRelayhost
description: >-
Adds an active relay host, used by domains and mailboxes whose
`relayhost` is set to its ID. Always `smtp:` (TLS when offered, no
SMTPS). Colons in `username` and `password` are stored escaped, but
not by edit/relayhost.
Messages: `relayhost_added`; errors `invalid_host`.
requestBody:
content:
application/json:
schema:
type: object
properties:
hostname:
type: string
description: "Next hop: `host`, `host:25`, `[host]:587` or `[192.0.2.1]:25`"
username:
type: string
description: SMTP user name, empty for no authentication
default: ""
password:
type: string
description: SMTP password
default: ""
required:
- hostname
example:
hostname: "[smtp.example.com]:587"
username: relay-user@example.com
password: Secret-Passphrase-42
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/resource:
post:
tags:
- Resources
summary: Create a resource
operationId: addResource
description: >-
Creates a bookable SOGo resource, also for domain admins. Its address
is made of the letters and digits of `description` (`Meeting Room 1` →
`MeetingRoom1@example.org`).
Messages: `resource_added`; errors `resource_invalid`,
`description_invalid`, `object_exists`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- domain
- description
- kind
properties:
domain:
type: string
description: Domain of the resource
description:
type: string
description: Name of the resource, also the source of its address
kind:
type: string
enum:
- location
- group
- thing
description: Type of resource
multiple_bookings:
type: [integer, string]
default: 0
description: >-
0 always free, -1 unlimited but busy when booked, n ≥ 1 at
most n overlapping bookings; below -1 means -1
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: 1 active, 0 inactive
example:
domain: example.org
description: Meeting Room 1
kind: location
multiple_bookings: 0
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/syncjob:
post:
summary: Create sync job
description: >-
Creates a sync job that copies the remote account `user1` into a local
mailbox; server and authentication come from the sync source. Needs the
`syncjobs` ACL; API keys must set `username`, users always sync into
their own mailbox. An invalid `mins_interval` or `exclude` answers
`access_denied`.
Messages: `mailbox_modified`; errors `no_user_defined`,
`imapsync_source_unavailable`, `imapsync_source_oauth_connect_required`,
`object_exists`, `imapsync_custom_param_invalid`.
operationId: addSyncJob
tags:
- Sync jobs
requestBody:
content:
application/json:
schema:
allOf:
- type: object
required:
- username
- source_id
- user1
- mins_interval
properties:
username:
type: string
description: >-
Local mailbox to sync into (`user2`), cannot be changed
later; users may leave it out
- $ref: "#/components/schemas/SyncJobAttributes"
example:
username: alice@example.org
source_id: 3
user1: alice@old-provider.example.com
password1: remote-password
mins_interval: 20
subfolder2: Imported
exclude: "(?i)spam|(?i)junk"
custom_params:
- o: folder
v: INBOX
delete2duplicates: 1
automap: 1
subscribeall: 1
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/syncjob_source:
post:
summary: Create sync source
description: >-
Creates a reusable IMAP server with its authentication that sync jobs
use by `source_id`. Needs the `syncjobs` ACL. Unless an admin creates
it, OAuth2 endpoints must resolve to public addresses. A
client_credentials source fetches its token on save and is saved even
when that fails.
Messages: `imapsync_source_added`, `imapsync_source_token_refresh_failed`;
errors `imapsync_source_host_invalid`, `imapsync_source_auth_invalid`,
`imapsync_source_oauth_invalid`, `imapsync_source_oauth_endpoint_invalid`,
`object_exists`.
operationId: addSyncJobSource
tags:
- Sync jobs
requestBody:
content:
application/json:
schema:
allOf:
- type: object
required:
- name
- host
- port
- $ref: "#/components/schemas/SyncJobSourceAttributes"
examples:
password:
summary: Password source for a domain
value:
name: Old provider
description: Migration from the old provider
host: imap.example.com
port: 993
enc: SSL
auth_type: PLAIN
scope: domain
domains:
- example.org
active: 1
client_credentials:
summary: XOAUTH2 source with an app token (Microsoft 365)
value:
name: M365 tenant
host: outlook.office365.com
port: 993
enc: SSL
auth_type: XOAUTH2
oauth_flow: client_credentials
oauth_token_endpoint: https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token
oauth_client_id: 11111111-2222-3333-4444-555555555555
oauth_client_secret: client-secret-value
oauth_scope: https://outlook.office365.com/.default
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/tls-policy-map:
post:
tags:
- Outgoing TLS Policy Map Overrides
summary: Create a TLS policy map
operationId: addTlsPolicyMap
description: >-
Sets the TLS policy for outgoing connections to a destination.
Messages: `tls_policy_map_entry_saved`; errors
`tls_policy_map_dest_invalid`, `tls_policy_map_parameter_invalid`,
`tls_policy_map_entry_exists`.
requestBody:
content:
application/json:
schema:
type: object
properties:
dest:
type: string
description: >-
Destination: a domain, `.example.org` for its subdomains or
a host like `[mail.example.org]:25`
policy:
type: string
description: >-
Postfix TLS security level (see
[smtp_tls_policy_maps](https://www.postfix.org/TLS_README.html#client_tls_policy))
enum:
- none
- may
- encrypt
- dane
- dane-only
- fingerprint
- verify
- secure
parameters:
type: string
description: Space-separated `name=value` attributes, may be empty
default: ""
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
default: 0
required:
- dest
- policy
example:
dest: example.com
policy: encrypt
parameters: protocols=>=TLSv1.2
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/transport:
post:
tags:
- Routing
summary: Create transport maps
operationId: addTransport
description: >-
Routes mail for each destination over a next hop; overrules
sender-dependent transports. Always `smtp:` (TLS when offered, no
SMTPS); addresses ending in `localhost` stay local. `username` and
`password` apply to all entries of the next hop.
Messages: `relayhost_added`; errors `transport_dest_exists`,
`invalid_destination`, `next_hop_interferes`,
`invalid_nexthop_authenticated`.
requestBody:
content:
application/json:
schema:
type: object
properties:
destination:
type: string
description: >-
Domains, `.example.org` for subdomains, `*` or addresses,
separated by spaces, commas, semicolons or line breaks;
with `is_mx_based` a regular expression for the MX name of
the recipient domain
nexthop:
type: string
description: "`host`, `host:25`, `[host]:25` or an IP address (bracketed automatically)"
username:
type: string
description: SMTP user name, empty for no authentication
default: ""
password:
type: string
description: SMTP password
default: ""
is_mx_based:
type: [boolean, integer, string]
description: 1 = `destination` is a regular expression for MX names
default: 0
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
default: 0
required:
- destination
- nexthop
example:
destination: example.com, .example.com
nexthop: "[mx.example.com]:25"
username: ""
password: ""
is_mx_based: "0"
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/alias:
post:
tags:
- Aliases
summary: Delete aliases
operationId: deleteAlias
description: >-
Deletes the aliases and the send-as rights granted for their addresses.
Distribution addresses of mailbox groups cannot be deleted here.
Messages: `alias_removed`; errors `alias_group_managed`.
requestBody:
content:
application/json:
schema:
type: array
description: IDs or addresses of the aliases (a single value works too)
items:
type: [integer, string]
example:
- 12
- info@example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/api-key:
post:
summary: Delete API keys
description: >-
Deletes API keys. Service keys from mailcow.conf cannot be deleted.
Messages: `api_key_deleted`; error `api_key_service_locked`.
operationId: deleteApiKey
tags:
- API Keys
requestBody:
required: true
content:
application/json:
schema:
type: array
description: IDs of the API keys
items:
type: [integer, string]
example:
- 3
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/app-passwd:
post:
tags:
- App Passwords
summary: Delete app passwords
operationId: deleteAppPassword
description: >-
Deletes app passwords by ID. Needs the user ACL `app_passwds`. The
first unknown or foreign ID stops the call.
requestBody:
required: true
content:
application/json:
schema:
type: array
description: App password IDs
items:
type: integer
example:
- 23
- 24
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/bcc:
post:
tags:
- Address Rewriting
summary: Delete BCC maps
operationId: deleteBccMap
description: >-
Deletes BCC maps by ID. Same callers as add/bcc. A non-numeric ID stops
the call.
Messages: `bcc_deleted`.
requestBody:
content:
application/json:
schema:
type: array
description: IDs of the BCC maps (a single value works too)
items:
type: [integer, string]
example:
- 3
- 4
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/dkim:
post:
summary: Delete DKIM keys
description: >-
Deletes the DKIM keys of domains. Answers `dkim_removed` also for
domains without a key.
operationId: deleteDkimKeys
tags:
- DKIM
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Domain names
items:
type: string
example:
- example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/domain:
post:
summary: Delete domains
description: >-
Deletes domains without mailboxes or resources, with their aliases,
alias domains and settings. Domain admins left without a domain are
deleted too. The DKIM key is kept.
Messages: `domain_removed`; error `domain_not_empty`.
operationId: deleteDomain
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Domain names
items:
type: string
example:
- example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/domain-admin:
post:
summary: Delete domain administrators
description: >-
Deletes domain administrators with their ACLs, two-factor
authentication and FIDO2 keys.
Messages: `domain_admin_removed`; error `username_invalid`.
operationId: deleteDomainAdmin
tags:
- Domain admin
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Usernames of the domain administrators
items:
type: string
example:
- domainadmin1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/domain-policy:
post:
summary: Delete entries of domain allow and deny lists
description: >-
Deletes allow and deny list entries of domains by `prefid`. Needs the
ACL `spam_policy`. Unknown IDs and entries of mailboxes answer
`access_denied`.
Messages: `item_deleted`.
operationId: deleteDomainPolicy
tags:
- Domain antispam policies
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Entry IDs (`prefid`)
items:
type: [integer, string]
example:
- 12
- 13
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/fwdhost:
post:
tags:
- Forwarding Hosts
summary: Delete forwarding hosts
operationId: deleteForwardingHost
description: >-
Removes forwarding hosts, answering `forwarding_host_removed` also for
hosts that do not exist.
requestBody:
content:
application/json:
schema:
type: array
description: Hosts as get/fwdhost lists them (`host`; a single value works too)
items:
type: string
example:
- 192.0.2.25
- "2001:db8::25"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/fwdhost/{host}:
get:
tags:
- Forwarding Hosts
summary: Get forwarding hosts
operationId: getForwardingHosts
description: >-
`all` lists the forwarding hosts; any logged-in role may read a single
address. Networks cannot be read one by one (the slash ends the path).
`{}` if there is none.
parameters:
- name: host
in: path
required: true
description: "`all` or the address of a forwarding host"
schema:
type: string
example: all
responses:
"200":
description: The list of forwarding hosts (`all`) or one host
content:
application/json:
schema:
anyOf:
- type: array
items:
$ref: "#/components/schemas/ForwardingHost"
- $ref: "#/components/schemas/ForwardingHost"
examples:
all:
summary: get/fwdhost/all
value:
- host: 192.0.2.25
source: relay.example.com
keep_spam: "no"
- host: "2001:db8::25"
source: relay.example.com
keep_spam: "no"
- host: 198.51.100.0/24
source: 198.51.100.0/24
keep_spam: "yes"
one:
summary: get/fwdhost/192.0.2.25
value:
host: 192.0.2.25
source: relay.example.com
keep_spam: "no"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/delete/mailbox:
post:
tags:
- Mailboxes
summary: Delete mailboxes
operationId: deleteMailbox
description: >-
Deletes mailboxes with all their data, including aliases that point
only to them. Also for domain admins; a mailbox user can delete its own
mailbox.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MailboxItems"
example:
- john.doe@example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/mailbox-group:
post:
summary: Delete mailbox groups
description: >-
Deletes groups with their address, send-as rights and grants. Members
keep their mailbox settings; another group's template may become
effective. Same permissions as edit.
Messages: `group_removed`.
operationId: deleteMailboxGroups
tags:
- Groups
requestBody:
content:
application/json:
schema:
type: array
description: Group ids
items:
type:
- integer
- string
example:
- 7
- 8
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/identity-link:
post:
summary: Remove identity links
description: >-
Removes the links of mailboxes to their Identity Provider users, e.g.
after an address moved to another user; the next sync run or login
links them again by email. Answers success also for mailboxes without a
link.
Messages: `iam_link_removed`.
operationId: deleteIdentityLinks
tags:
- Identity Provider
requestBody:
content:
application/json:
schema:
type: array
description: Mailboxes
items:
type: string
example:
- alice@example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/mailq:
post:
summary: Delete queued messages
description: >-
Deletes messages from the Postfix queue. To empty the whole queue use
`super_delete` of `POST /api/v1/edit/mailq`.
Messages: `queue_command_success`; errors `Error: command failed: ...`,
`unknown`.
operationId: deleteQueuedMessages
tags:
- Queue Manager
requestBody:
content:
application/json:
schema:
description: Queue IDs (a single ID works too)
oneOf:
- type: array
items:
type: string
- type: string
example:
- B98C6260CA1
- 4C1E8260D02
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/oauth2-client:
post:
summary: Delete OAuth2 clients
description: >-
Deletes OAuth2 clients but not their tokens; revoke these first with
`revoke_tokens` of `edit/oauth2-client`.
Messages: `items_deleted`.
operationId: deleteOAuth2Client
tags:
- oAuth Clients
requestBody:
required: true
content:
application/json:
schema:
type: array
description: IDs of the clients
items:
type: [integer, string]
example:
- 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/qitem:
post:
summary: Delete quarantined messages
description: >-
Deletes quarantine items without releasing or learning them. Domain
admins and mailbox users may delete their own items if the quarantine
module is allowed for them. Admins get `item_deleted` even for unknown
IDs.
operationId: deleteQuarantineItems
tags:
- Quarantine
requestBody:
content:
application/json:
schema:
description: IDs of quarantine items (a single ID works too)
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
example:
- "33"
- "34"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/qitem:
post:
summary: Release or learn quarantined messages
description: >-
By `attr.action`: `release` and `learnham` both deliver the message,
delete the item and learn it as ham; `learnspam` deletes it and learns
it as spam. Domain
admins and mailbox users may act on their own items if the quarantine
module is allowed for them. A failed delivery stops the remaining
items.
Messages: `item_released`, `learned_ham`, `qlearn_spam`; errors
`release_send_failed`, `ham_learn_error`, `spam_learn_error`.
operationId: editQuarantineItems
tags:
- Quarantine
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: ID or list of IDs of quarantine items
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
attr:
type: object
properties:
action:
type: string
enum:
- release
- learnham
- learnspam
required:
- action
required:
- items
- attr
example:
items:
- "33"
- "34"
attr:
action: release
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/recipient_map:
post:
tags:
- Address Rewriting
summary: Delete recipient maps
operationId: deleteRecipientMap
description: >-
Deletes recipient maps by ID. Answers `recipient_map_entry_deleted`
also for IDs that do not exist; a non-numeric ID stops the call.
requestBody:
content:
application/json:
schema:
type: array
description: IDs of the recipient maps (a single value works too)
items:
type: [integer, string]
example:
- 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/relayhost:
post:
tags:
- Routing
summary: Delete sender-dependent transports
operationId: deleteRelayhost
description: >-
Deletes sender-dependent transports by ID, answering
`relayhost_removed` also for IDs that do not exist. Domains that used
one fall back to the default route; the `relayhost` of mailboxes is not
reset.
requestBody:
content:
application/json:
schema:
type: array
description: IDs of the sender-dependent transports (a single value works too)
items:
type: [integer, string]
example:
- 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/resource:
post:
tags:
- Resources
summary: Delete resources
operationId: deleteResource
description: >-
Deletes resources and their SOGo data, also for domain admins.
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Resource addresses
items:
type: string
example:
- MeetingRoom1@example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/syncjob:
post:
summary: Delete sync jobs
description: >-
Deletes sync jobs. Needs the `syncjobs` ACL and access to the mailbox of
each job. The OAuth2 token of the remote account is deleted when no
other job uses it.
Messages: `deleted_syncjob`.
operationId: deleteSyncJobs
tags:
- Sync jobs
requestBody:
content:
application/json:
schema:
type: array
description: Job ids
items:
type:
- integer
- string
example:
- 12
- 13
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/syncjob_source:
post:
summary: Delete sync sources
description: >-
Deletes sync sources that no job uses. Needs the `syncjobs` ACL and edit
rights on the source.
Messages: `imapsync_source_deleted`; errors `imapsync_source_in_use`.
operationId: deleteSyncJobSources
tags:
- Sync jobs
requestBody:
content:
application/json:
schema:
type: array
description: Source ids
items:
type:
- integer
- string
example:
- 3
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/tls-policy-map:
post:
tags:
- Outgoing TLS Policy Map Overrides
summary: Delete TLS policy maps
operationId: deleteTlsPolicyMap
description: >-
Deletes TLS policy maps by ID. Answers `tls_policy_map_entry_deleted`
also for IDs that do not exist; a non-numeric ID stops the call.
requestBody:
content:
application/json:
schema:
type: array
description: IDs of the TLS policy maps (a single value works too)
items:
type: [integer, string]
example:
- 2
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/transport:
post:
tags:
- Routing
summary: Delete transport maps
operationId: deleteTransport
description: >-
Deletes transport maps by ID, answering `relayhost_removed` also for
IDs that do not exist.
requestBody:
content:
application/json:
schema:
type: array
description: IDs of the transport maps (a single value works too)
items:
type: [integer, string]
example:
- 4
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/mailbox/tag/{mailbox}:
post:
tags:
- Mailboxes
summary: Remove tags from a mailbox
operationId: deleteMailboxTags
description: >-
Removes tags from the mailbox, also for domain admins. Answers "Cannot
delete item" when no tag was sent.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Tag names
items:
type: string
example:
- sales
- trainee
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/domain/tag/{domain}:
post:
summary: Remove tags of a domain
description: >-
Removes tags from a domain. Answers `domain_modified` also for tags the
domain did not have.
operationId: deleteDomainTags
tags:
- Domains
parameters:
- name: domain
in: path
required: true
description: Domain name
schema:
type: string
example: example.org
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Tag names
items:
type: string
example:
- customer
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/alias:
post:
tags:
- Aliases
summary: Update aliases
operationId: editAlias
description: >-
Changes the aliases in `items`; fields not sent keep their value,
except the `goto_*` flags, which are reset to 0. An alias that discards
or learns its mail therefore needs its `goto_*` flag in every edit,
else nothing is saved while the answer still says `alias_modified`.
Invalid destinations are dropped; if none remains, nothing is saved.
Messages: `alias_modified`; errors `alias_invalid`,
`alias_group_managed`, `goto_invalid`, `is_not_primary_alias`.
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: IDs or addresses of the aliases, a single value or a list
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
attr:
type: object
properties:
address:
type: string
description: New alias address, `@example.org` for a catch-all
goto:
type: string
description: >-
New destination addresses, replacing the current ones;
ignored if a `goto_*` flag is 1
goto_null:
type: [boolean, integer, string]
description: 1 = discard the mail silently
default: 0
goto_spam:
type: [boolean, integer, string]
description: 1 = learn the mail as spam
default: 0
goto_ham:
type: [boolean, integer, string]
description: 1 = learn the mail as ham
default: 0
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
sogo_visible:
type: [boolean, integer, string]
description: 1 = selectable sender in SOGo
internal:
type: [boolean, integer, string]
description: 1 = only reachable from its own domain and its alias domains
sender_allowed:
type: [boolean, integer, string]
description: 1 = the destination mailboxes may send as this alias
public_comment:
type: string
description: Comment shown to the users
private_comment:
type: string
description: Comment for administrators
expand_alias:
type: [boolean, integer]
description: >-
1 = only create the missing copies of the alias in the
alias domains of its domain; other attributes are
ignored
required:
- items
- attr
example:
items:
- 12
attr:
goto: anna@example.org,ben@example.org,carla@example.org
active: "1"
public_comment: Sales team
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/api-key:
post:
summary: Edit API keys
description: >-
Changes API keys; fields not sent keep their value. `regen_key` sets a
new random value, which locks out clients using the old one. Service
keys from mailcow.conf cannot be changed.
Messages: `api_key_modified`; errors `api_key_service_locked`,
`api_key_network_invalid`, `ip_list_empty`.
operationId: editApiKey
tags:
- API Keys
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
items:
description: ID of the API key, or a list of IDs
oneOf:
- type: [integer, string]
- type: array
items:
type: [integer, string]
attr:
allOf:
- $ref: "#/components/schemas/ApiKeyAttributes"
- type: object
properties:
regen_key:
type: [integer, string, boolean]
description: 1 = generate a new key value
default: 0
required:
- items
- attr
example:
items:
- 3
attr:
allow_from:
- 192.0.2.10
- 198.51.100.0/24
regen_key: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/domain:
post:
summary: Edit domains
description: >-
Changes domains. Quotas are in MiB. Fields not sent keep their value,
so do `aliases`, `maxquota` and `quota` sent as 0 or empty. `tags` are
added; a tag the domain has already ends the call without an answer
after saving the rest. Domain admins can change only `description`,
`gal` and `tags`.
Messages: `domain_modified`; errors `domain_invalid`,
`max_quota_in_use`, `mailboxes_in_use`, `aliases_in_use`.
operationId: editDomain
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Domain name or list of domain names
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
properties:
description:
type: string
description: Description
aliases:
type: [integer, string]
description: Max. number of aliases
mailboxes:
type: [integer, string]
description: Max. number of mailboxes
defquota:
type: [integer, string]
description: Default quota of new mailboxes in MiB
maxquota:
type: [integer, string]
description: Max. quota per mailbox in MiB
quota:
type: [integer, string]
description: Quota of the whole domain in MiB
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Domain active
gal:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Global address list in SOGo
backupmx:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Relay this domain (backup MX)
relay_all_recipients:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Relay all recipients; 1 sets `backupmx`
relay_unknown_only:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: >-
Relay only recipients without a local mailbox; 1 sets
`backupmx` and `relay_all_recipients`
relayhost:
type: [integer, string]
description: >-
ID of the sender-dependent transport (get/relayhost/all)
the domain sends through, 0 = none
tags:
type: array
items:
type: string
description: Tags to add
example:
items:
- example.org
attr:
description: Example Org
aliases: 400
mailboxes: 20
defquota: 3072
maxquota: 10240
quota: 51200
active: 1
gal: 1
backupmx: 0
relay_all_recipients: 0
relay_unknown_only: 0
relayhost: 0
tags:
- premium
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/domain/footer:
post:
summary: Set the domain-wide footer
description: >-
Sets the footer of all outgoing mail of the domains; fields not sent are
emptied. Placeholders: `{= auth_user =}`, `{= from_user =}`,
`{= from_name =}`, `{= from_addr =}`, `{= from_domain =}` and custom
mailbox attributes.
Messages: `domain_footer_modified`; error `domain_invalid`.
operationId: editDomainFooter
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Domain name or list of domain names
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
properties:
html:
type: string
default: ""
description: HTML footer
plain:
type: string
default: ""
description: Plain text footer
skip_replies:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: No footer in replies
exclude:
description: >-
Mailboxes, aliases and alias domains without footer;
unknown entries are skipped (`username_invalid`)
oneOf:
- type: string
- type: array
items:
type: string
example:
items:
- example.org
attr:
html: "<p>Example Org &middot; {= from_name =}</p>"
plain: "Example Org - {= from_name =}"
skip_replies: 1
exclude:
- noreply@example.org
- example.com
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/fail2ban:
post:
summary: Edit Fail2Ban settings, bans and filters
description: >-
By `attr.action`: `unban`, `whitelist` and `blacklist` unban, allowlist
or deny the networks in `items`; `unban-all` lifts all active bans;
`edit-regex` replaces the regex filters with `attr.regex`,
`reset-regex` restores the defaults. Without `action` the settings are
saved: fields not sent keep their value, but `ban_time_increment` and
`manage_external` become 0, and values out of range are clamped. The
same happens for `unban`, `whitelist`, `blacklist` or `reset-regex`
without `items`.
Messages: `f2b_modified`, `object_modified`; errors
`network_host_invalid`, `reset_f2b_regex`.
operationId: editFail2Ban
tags:
- Fail2Ban
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: Networks or IPs for `unban`, `whitelist`, `blacklist` (single value or list)
oneOf:
- type: array
items:
type: string
- type: string
attr:
type: object
properties:
action:
type: string
enum:
- unban
- whitelist
- blacklist
- unban-all
- edit-regex
- reset-regex
regex:
type: array
items:
type: string
description: "`edit-regex`: the regex filters; the first group must match the IP"
ban_time:
type: [integer, string]
description: Ban time in seconds (min. 60)
ban_time_increment:
type: [boolean, integer, string]
description: 1 = the ban time grows with every ban of a network; not sent = 0
max_ban_time:
type: [integer, string]
description: Maximum ban time in seconds (min. 60)
max_attempts:
type: [integer, string]
description: Failed logins within `retry_window` that lead to a ban (min. 1)
retry_window:
type: [integer, string]
description: Window in seconds for `max_attempts` (min. 1)
netban_ipv4:
type: [integer, string]
description: IPv4 prefix length that is banned (8-32)
netban_ipv6:
type: [integer, string]
description: IPv6 prefix length that is banned (8-128)
whitelist:
type: string
description: Allowlist, networks or host names separated by space, comma, semicolon or newline; replaces the list
blacklist:
type: string
description: Denylist, networks separated by space, comma, semicolon or newline; replaces the list
manage_external:
type: [boolean, integer, string]
description: 1 = netfilter sets no rules, block externally with the banlist; not sent = 0
required:
- attr
examples:
settings:
summary: Save the settings
value:
items: []
attr:
ban_time: "1800"
ban_time_increment: "1"
max_ban_time: "86400"
max_attempts: "10"
retry_window: "600"
netban_ipv4: "32"
netban_ipv6: "128"
whitelist: |-
192.0.2.0/24
mail.example.org
blacklist: 198.51.100.66/32
manage_external: "0"
unban:
summary: Unban a network
value:
items:
- 203.0.113.7/32
attr:
action: unban
regex:
summary: Replace the regex filters
value:
items:
- self
attr:
action: edit-regex
regex:
- "^mailcow UI: Invalid password for .+ by ([0-9a-f\\.:]+)$"
- "^Rspamd UI: Invalid password by ([0-9a-f\\.:]+)$"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/mailbox:
post:
tags:
- Mailboxes
summary: Update mailboxes
operationId: editMailbox
description: >-
Changes mailboxes; fields not sent keep their value. Also for domain
admins; without the matching ACL their changes to `sogo_access`,
protocols and `relayhost` are ignored silently and
`extended_sender_acl` is refused. Quota 0 (unlimited) needs the
`unlimited_quota` ACL.
Messages: `mailbox_modified`; errors `mailbox_quota_exceeded`,
`password_complexity`, `sender_acl_invalid`,
`extended_sender_acl_denied`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
$ref: "#/components/schemas/MailboxEdit"
example:
items:
- john.doe@example.org
attr:
name: John Doe
quota: 5120
active: 1
protocol_access:
- imap
- smtp
- sieve
- dav
sender_acl:
- sales@example.org
- "@example.com"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/mailbox/custom-attribute:
post:
tags:
- Mailboxes
summary: Set custom attributes of mailboxes
operationId: editMailboxCustomAttributes
description: >-
Replaces the custom attributes (free key/value pairs) of the mailboxes:
`attribute[i]` gets `value[i]`, all others are removed. Also for domain
admins.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
properties:
attribute:
description: Attribute names (a single string is one name)
oneOf:
- type: string
- type: array
items:
type: string
value:
description: Values, in the order of `attribute`
oneOf:
- type: string
- type: array
items:
type: string
example:
items:
- john.doe@example.org
attr:
attribute:
- department
- employee_id
value:
- Sales
- "4711"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/mailbox-group:
post:
summary: Update mailbox groups
description: >-
Changes groups; fields not sent keep their value. The domain cannot be
changed, and members from the identity sync cannot be removed here.
Domain admins need the `mailbox_groups` ACL and cannot edit groups with
send-as addresses or grants outside their domains.
Messages: `group_modified`; errors `group_member_idp` and those of add.
operationId: editMailboxGroups
tags:
- Groups
requestBody:
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: >-
Group ids, a list or a single id. An `id` inside `attr`
replaces `items`.
oneOf:
- type: array
items:
type:
- integer
- string
- type:
- integer
- string
attr:
allOf:
- $ref: "#/components/schemas/MailboxGroupAttributes"
- type: object
properties:
reapply_template:
type:
- boolean
- integer
- string
description: >-
Admins only: apply the effective templates to all
members again, also when nothing changed
default: 0
example:
items:
- 7
attr:
add_members:
- carol@example.org
remove_members:
- bob@example.org
sogo_grants:
- owner: shared@example.org
type: Calendar
folder: personal
access: write
subscribe: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/identity-provider-sync:
post:
summary: Request an identity sync run
description: >-
Queues an identity sync run (Keycloak and LDAP) that starts within a
minute, see `GET /api/v1/get/identity-provider/sync-status`. An
identical pending request is reused.
Messages: `iam_sync_requested`; errors `iam_sync_mode_invalid`,
`iam_sync_unavailable`.
operationId: requestIdentitySync
tags:
- Identity Provider
requestBody:
content:
application/json:
schema:
type: object
required:
- attr
properties:
items:
description: Not used
attr:
type: object
properties:
mode:
type: string
description: >-
`preview` lists the changes without applying them,
`run` applies them, `force` applies them without the
change limit (`offboarding_limit`)
enum:
- preview
- run
- force
default: run
example:
attr:
mode: preview
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/mailq:
post:
summary: Act on the mail queue
description: >-
Runs a Postfix queue command. `hold`, `unhold` and `deliver` act on the
queue IDs in `items` and do nothing without them; `flush` retries the
whole queue, `super_delete` deletes every queued message.
Messages: `queue_command_success`; errors `Error: command failed: ...`,
`unknown`.
operationId: editMailQueue
tags:
- Queue Manager
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: Queue ID or list of queue IDs (for `hold`, `unhold`, `deliver`)
oneOf:
- type: array
items:
type: string
- type: string
attr:
type: object
properties:
action:
type: string
enum:
- hold
- unhold
- deliver
- flush
- super_delete
required:
- action
required:
- attr
examples:
hold:
summary: Hold two messages
value:
items:
- B98C6260CA1
- 4C1E8260D02
attr:
action: hold
flush:
summary: Flush the whole queue
value:
items: []
attr:
action: flush
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/pushover:
post:
tags:
- Mailbox user settings
summary: Set the Pushover notifications of mailboxes
operationId: editPushover
description: >-
Saves the Pushover settings (push notification on new mail) of the
mailboxes; `delete: "true"` removes them. Needs the user ACL
`pushover`; domain admins need their own ACL `pushover`. `key` and
`token` are required the first time; later, empty fields keep their
value.
Messages: `pushover_settings_edited`; errors `pushover_key`,
`pushover_token`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
properties:
key:
type: string
description: Pushover user key, 30 letters and digits
token:
type: string
description: Pushover application token, 30 letters and digits
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
title:
type: string
description: Title of the notification (default "Mail")
text:
type: string
description: Text of the notification
senders:
type: string
description: Only notify for these senders (separated by comma, space or semicolon)
senders_regex:
type: string
description: Only notify for senders matching this regular expression
evaluate_x_prio:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: 1 sends high-priority mail as high-priority notification (0 when not sent)
only_x_prio:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: 1 notifies for high-priority mails only (0 when not sent)
sound:
type: string
description: Pushover sound name (empty when not sent)
delete:
type: string
enum:
- "true"
description: '"true" removes the Pushover settings, other fields are ignored'
example:
items:
- john.doe@example.org
attr:
key: uQiRzpo4DXghDmr9QzzfQu27cmVRsG
token: azGDORePK8gMaC0QOYAMyEEuzJnyUi
active: 1
title: New mail
text: You've got mail
senders: boss@example.org
evaluate_x_prio: 1
only_x_prio: 0
sound: pushover
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/quarantine_notification:
post:
tags:
- Quarantine
summary: Set the quarantine notification interval of mailboxes
operationId: editQuarantineNotification
description: >-
How often the mailbox user gets a summary of quarantined mail. Needs
the user ACL `quarantine_notification`; a mailbox user may change only
its own. An invalid value answers `access_denied`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
required:
- quarantine_notification
properties:
quarantine_notification:
type: string
enum:
- never
- hourly
- daily
- weekly
example:
items:
- john.doe@example.org
attr:
quarantine_notification: daily
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/syncjob:
post:
summary: Update sync jobs
description: >-
Changes sync jobs; fields not sent keep their value, an empty `user1` or
`password1` keeps the stored one. The local mailbox cannot be changed.
Needs the `syncjobs` ACL and access to the mailbox of each job.
Messages: `mailbox_modified`; errors as for add.
operationId: editSyncJobs
tags:
- Sync jobs
requestBody:
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: >-
Job ids, a list or a single id. An `id` inside `attr`
replaces `items`.
oneOf:
- type: array
items:
type:
- integer
- string
- type:
- integer
- string
attr:
allOf:
- $ref: "#/components/schemas/SyncJobAttributes"
- type: object
properties:
last_run:
description: Any value except null resets the last run time (the job is due again)
success:
description: Any value except null resets the result of the last run
prio:
type:
- integer
- string
description: >-
Admins only: queue priority, higher runs first (see
`edit/syncjob/run_next`)
example:
items:
- 12
- 13
attr:
active: 0
mins_interval: 60
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/syncjob/run_next:
post:
summary: Run sync jobs next
description: >-
Moves sync jobs to the front of the queue so the runner starts them
next; their `last_run` and `success` are cleared.
Messages: `imapsync_run_next_done`; errors `imapsync_job_running`.
operationId: runSyncJobsNext
tags:
- Sync jobs
requestBody:
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
description: Job ids
type: array
items:
type:
- integer
- string
attr:
description: Not used
type: object
example:
items:
- 12
attr: {}
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/syncjob_source:
post:
summary: Update sync sources
description: >-
Changes sync sources; fields not sent keep their value, an empty
`oauth_client_secret` keeps the stored one. Needs the `syncjobs` ACL and
edit rights: own sources, for domain admins also those of their
mailboxes. Changing the server or OAuth2 client drops stored tokens and,
like turning off `verify_cert`, needs access to every mailbox whose jobs
use the source.
Messages: `imapsync_source_modified`,
`imapsync_source_token_refresh_failed`; errors
`imapsync_source_used_by_others` and those of add.
operationId: editSyncJobSources
tags:
- Sync jobs
requestBody:
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: >-
Source ids, a list or a single id. An `id` inside `attr`
replaces `items`.
oneOf:
- type: array
items:
type:
- integer
- string
- type:
- integer
- string
attr:
$ref: "#/components/schemas/SyncJobSourceAttributes"
example:
items:
- 3
attr:
description: Migration finished in December
scope: user
users:
- alice@example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/syncjob_source/refresh_token:
post:
summary: Refresh the token of a sync source
description: >-
Fetches a new OAuth2 token for a client_credentials source now; tokens
are otherwise refreshed before they expire. Needs the `syncjobs` ACL and
edit rights on the source.
Messages: `imapsync_source_token_refreshed`; errors
`imapsync_source_refresh_unsupported`,
`imapsync_source_token_refresh_failed`.
operationId: refreshSyncJobSourceToken
tags:
- Sync jobs
requestBody:
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
description: Source id (the first entry is used)
type: array
items:
type:
- integer
- string
attr:
description: Not used
type: object
example:
items:
- 5
attr: {}
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/imapsync_settings:
post:
summary: Update global sync job settings
description: >-
Sets how many sync jobs run at the same time and the bandwidth limit of
each sync job process; a lower `maxbytespersecond` of a job still
applies.
Messages: `max_parallel_saved`; errors `imapsync_max_parallel_invalid`,
`imapsync_max_kb_per_second_invalid`.
operationId: editSyncJobSettings
tags:
- Sync jobs
requestBody:
content:
application/json:
schema:
type: object
required:
- attr
properties:
items:
description: Not used
attr:
type: object
required:
- max_parallel
properties:
max_parallel:
type:
- integer
- string
description: Sync jobs running at the same time, 1-32
minimum: 1
maximum: 32
max_kb_per_second:
type:
- integer
- string
description: Bandwidth limit per sync job process in KB/s; 0, empty or not sent = unlimited
default: 0
minimum: 0
maximum: 10485760
example:
attr:
max_parallel: 4
max_kb_per_second: 2000
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/user-acl:
post:
tags:
- Mailboxes
summary: Set the ACL of mailboxes
operationId: editUserAcl
description: >-
Sets the user ACL (what the mailbox user may change in the UI): listed
ACLs on, all others off. Domain admins can change only ACLs they have
themselves. Answers `acl_saved`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
properties:
user_acl:
description: ACLs to switch on (a single string is one ACL); an empty list switches all off
oneOf:
- $ref: "#/components/schemas/UserAclName"
- type: array
items:
$ref: "#/components/schemas/UserAclName"
example:
items:
- john.doe@example.org
attr:
user_acl:
- spam_alias
- tls_policy
- spam_score
- spam_policy
- delimiter_action
- eas_reset
- pushover
- quarantine
- quarantine_notification
- app_passwds
- pw_reset
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/alias/{id}:
get:
tags:
- Aliases
summary: Get aliases
operationId: getAliases
description: >-
`all` lists the aliases of the domains the caller manages, an ID or
address returns one alias. Mailbox addresses are not listed. `{}` if
there is none.
parameters:
- name: id
in: path
required: true
description: "`all`, or the ID or address of an alias"
schema:
type: string
example: all
responses:
"200":
description: The list of aliases (`all`) or one alias
content:
application/json:
schema:
anyOf:
- type: array
items:
$ref: "#/components/schemas/Alias"
- $ref: "#/components/schemas/Alias"
examples:
all:
summary: get/alias/all
value:
- in_primary_domain: ""
id: 12
domain: example.org
public_comment: Sales team
private_comment: null
goto: anna@example.org,ben@example.org
address: sales@example.org
is_catch_all: 0
internal: 0
active: 1
active_int: 1
sogo_visible: 1
sogo_visible_int: 1
sender_allowed: 1
group_id: null
group_name: null
created: "2026-10-26 14:43:58"
modified: "2026-11-08 20:38:01"
- in_primary_domain: example.org
id: 20
domain: example.net
public_comment: ""
private_comment: ""
goto: null@localhost
address: "@example.net"
is_catch_all: 1
internal: 0
active: 1
active_int: 1
sogo_visible: 0
sogo_visible_int: 0
sender_allowed: 0
group_id: null
group_name: null
created: "2026-11-02 09:12:40"
modified: null
one:
summary: get/alias/12
value:
in_primary_domain: ""
id: 12
domain: example.org
public_comment: Sales team
private_comment: null
goto: anna@example.org,ben@example.org
address: sales@example.org
is_catch_all: 0
internal: 0
active: 1
active_int: 1
sogo_visible: 1
sogo_visible_int: 1
sender_allowed: 1
group_id: null
group_name: null
created: "2026-10-26 14:43:58"
modified: "2026-11-08 20:38:01"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/alias/all/{domains}:
get:
tags:
- Aliases
summary: Get the aliases of domains
operationId: getAliasesByDomain
description: >-
Lists the aliases of the named domains or alias domains, skipping
domains the caller does not manage. `{}` if there is none.
parameters:
- name: domains
in: path
required: true
description: Comma-separated domain names
schema:
type: string
example: example.org,example.net
responses:
"200":
description: The list of aliases
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Alias"
example:
- in_primary_domain: ""
id: 12
domain: example.org
public_comment: Sales team
private_comment: null
goto: anna@example.org,ben@example.org
address: sales@example.org
is_catch_all: 0
internal: 0
active: 1
active_int: 1
sogo_visible: 1
sogo_visible_int: 1
sender_allowed: 1
group_id: null
group_name: null
created: "2026-10-26 14:43:58"
modified: "2026-11-08 20:38:01"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/time_limited_aliases/{mailbox}:
get:
tags:
- Mailbox user settings
summary: Get the time-limited aliases of a mailbox
operationId: getTimeLimitedAliases
description: >-
The valid or permanent time-limited aliases of the mailbox. `{}` if
none or no access.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: List of aliases
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/TimeLimitedAlias"
example:
- address: kahd.osuwe@example.org
goto: john.doe@example.org
description: Online shop registration
validity: 1795699200
created: "2026-11-10 09:00:00"
modified: null
permanent: 0
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/time_limited_alias:
post:
tags:
- Mailbox user settings
summary: Update time-limited aliases
operationId: editTimeLimitedAlias
description: >-
Sets a new expiry (`validity` hours from now) or makes the aliases
permanent. Needs the user ACL `spam_alias`. Without `validity` or a
true `permanent` nothing changes.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Alias address or list of addresses
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
properties:
validity:
type: [integer, string]
description: Hours from now until the alias expires (not range-checked); ends a permanent state
permanent:
type: [boolean, integer, string]
description: true makes the alias permanent (wins over `validity`)
example:
items:
- kahd.osuwe@example.org
attr:
validity: 24
permanent: 0
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/time_limited_alias:
post:
tags:
- Mailbox user settings
summary: Delete time-limited aliases
operationId: deleteTimeLimitedAlias
description: >-
Deletes time-limited aliases. Needs the user ACL `spam_alias`.
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Alias addresses
items:
type: string
example:
- kahd.osuwe@example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/pushover-test:
post:
tags:
- Mailbox user settings
summary: Verify the Pushover credentials of mailboxes
operationId: testPushover
description: >-
Checks the stored Pushover credentials of each mailbox with the
Pushover API; `attr` is not used. Same access as `edit/pushover`.
Answers "Pushover API OK (200): ..." or "Pushover API ERR (code): ...";
a mailbox without settings stops the call.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
description: Not used
example:
items:
- john.doe@example.org
attr: {}
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/delimiter_action:
post:
tags:
- Mailbox user settings
summary: Set the handling of tagged mail
operationId: editDelimiterAction
description: >-
Handling of mail to `user+tag@example.org`: move to the subfolder "tag"
(`subfolder`), add "[tag]" to the subject (`subject`) or nothing
(`none`, also for other values). Needs the user ACL `delimiter_action`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
properties:
tagged_mail_handler:
type: string
enum:
- subfolder
- subject
- none
example:
items:
- john.doe@example.org
attr:
tagged_mail_handler: subfolder
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/tls_policy:
post:
tags:
- Mailbox user settings
summary: Set the TLS policy of mailboxes
operationId: editTlsPolicy
description: >-
Enforces TLS for incoming and/or outgoing mail; fields not sent keep
their value. Needs the user ACL `tls_policy`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
properties:
tls_enforce_in:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: 1 accepts incoming mail only over TLS
tls_enforce_out:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: 1 sends outgoing mail only over TLS
example:
items:
- john.doe@example.org
attr:
tls_enforce_in: 1
tls_enforce_out: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/spam-score:
get:
tags:
- Mailbox user settings
summary: Get the default spam score
operationId: getDefaultSpamScore
description: >-
The spam thresholds of the session user; for API keys the Rspamd
default (`5,15` if Rspamd is unreachable).
responses:
"200":
description: Thresholds
content:
application/json:
schema:
$ref: "#/components/schemas/SpamScore"
example:
score: "8,15"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/api-key/{id}:
get:
summary: Get API key
description: One API key with its value. A read-only API key gets `{}`.
operationId: getApiKey
tags:
- API Keys
parameters:
- name: id
in: path
required: true
description: ID of the API key
schema:
type: integer
example: 3
responses:
"200":
description: The API key, `{}` if there is none with this ID or for a read-only API key
content:
application/json:
schema:
$ref: "#/components/schemas/ApiKey"
example:
id: 3
description: provisioning
access: rw
api_key: 1B7E2C-94F0A3-6D5B18-C2E7F4-03A9D6
allow_from:
- 192.0.2.10
- 2001:db8::/64
skip_ip_check: 0
service: 0
active: 1
created: "2026-11-02 09:12:44"
modified: "2026-11-05 16:40:02"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/api-key/all:
get:
summary: Get API keys
description: >-
Lists all API keys with their values, service keys first. A read-only
API key gets `{}`.
operationId: getApiKeys
tags:
- API Keys
responses:
"200":
description: The API keys, `{}` if there are none or for a read-only API key
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ApiKey"
example:
- id: 1
description: API_KEY
access: rw
api_key: 8F2D41-0C9A7B-5E3F12-AB46C0-77D1E9
allow_from:
- 192.0.2.0/24
skip_ip_check: 0
service: 1
active: 1
created: "2026-09-21 10:20:00"
modified: null
- id: 3
description: provisioning
access: rw
api_key: 1B7E2C-94F0A3-6D5B18-C2E7F4-03A9D6
allow_from:
- 192.0.2.10
- 2001:db8::/64
skip_ip_check: 0
service: 0
active: 1
created: "2026-11-02 09:12:44"
modified: "2026-11-05 16:40:02"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/app-passwd/all/{mailbox}:
get:
tags:
- App Passwords
summary: Get the app passwords of a mailbox
operationId: getAppPasswords
description: >-
The app passwords of the mailbox, with password hashes. `{}` if none or
no access.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: List of app passwords
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/AppPassword"
example:
- id: 23
name: Thunderbird
mailbox: john.doe@example.org
domain: example.org
password: "{BLF-CRYPT}$2y$10$..."
created: "2026-11-08 20:38:01"
modified: null
imap_access: 1
smtp_access: 1
dav_access: 0
eas_access: 0
pop3_access: 0
sieve_access: 1
active: 1
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/app-passwd/all:
get:
tags:
- App Passwords
summary: Get the app passwords of the logged-in mailbox
operationId: getOwnAppPasswords
description: >-
The app passwords of the logged-in mailbox user. API keys get `{}`; use
`get/app-passwd/all/{mailbox}`.
responses:
"200":
description: List of app passwords
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/AppPassword"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/app-passwd/{id}:
get:
tags:
- App Passwords
summary: Get an app password (broken)
operationId: getAppPassword
description: >-
Broken: always ends with an error and an empty body. Use
`get/app-passwd/all/{mailbox}`.
parameters:
- name: id
in: path
required: true
description: App password ID
schema:
type: integer
example: 23
responses:
"200":
description: Empty body
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/app-passwd:
post:
tags:
- App Passwords
summary: Update app passwords
operationId: editAppPassword
description: >-
Changes app passwords by ID; fields not sent keep their value. Needs
the user ACL `app_passwds`.
Messages: `object_modified`; errors `app_passwd_id_invalid`,
`password_complexity`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: App password ID or list of IDs
oneOf:
- type: integer
- type: array
items:
type: integer
attr:
type: object
properties:
username:
type: string
description: Mailbox the app passwords belong to (required for API keys)
app_name:
type: string
app_passwd:
type: string
format: password
description: New password; changed only together with `app_passwd2`
app_passwd2:
type: string
format: password
protocols:
description: Replaces the allowed protocols
type: array
items:
type: string
enum:
- imap_access
- smtp_access
- pop3_access
- sieve_access
- dav_access
- eas_access
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
example:
items:
- 23
attr:
username: john.doe@example.org
active: 0
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/bcc/{id}:
get:
tags:
- Address Rewriting
summary: Get BCC maps
operationId: getBccMaps
description: >-
`all` lists the BCC maps of the domains the caller manages, an ID
returns one map with an extra member `"0": null`. `{}` if there is
none.
parameters:
- name: id
in: path
required: true
description: "`all` or the ID of a BCC map"
schema:
type: string
example: all
responses:
"200":
description: The list of BCC maps (`all`) or one BCC map
content:
application/json:
schema:
anyOf:
- type: array
items:
$ref: "#/components/schemas/BccMap"
- $ref: "#/components/schemas/BccMap"
examples:
all:
summary: get/bcc/all
value:
- id: 3
local_dest: "@example.org"
bcc_dest: archive@example.com
active: 1
type: rcpt
created: "2026-11-03 10:15:22"
domain: example.org
modified: null
one:
summary: get/bcc/3
value:
id: 3
local_dest: "@example.org"
bcc_dest: archive@example.com
active: 1
type: rcpt
created: "2026-11-03 10:15:22"
domain: example.org
modified: null
"0": null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/dkim/{domain}:
get:
summary: Get the DKIM key of a domain
description: >-
The DKIM public key of a domain or alias domain and the TXT record for
`<selector>._domainkey.<domain>`. `privkey` is empty unless
`SHOW_DKIM_PRIV_KEYS` is enabled.
operationId: getDkimKey
tags:
- DKIM
parameters:
- name: domain
in: path
required: true
description: Domain or alias domain name
schema:
type: string
example: example.org
responses:
"200":
description: The DKIM key
content:
application/json:
schema:
$ref: "#/components/schemas/DkimKey"
example:
pubkey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxV3...IDAQAB
length: "2048"
dkim_txt: v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxV3...IDAQAB
dkim_selector: dkim
privkey: ""
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/add/dkim_import:
post:
summary: Import a DKIM key
description: >-
Imports an RSA private key as the DKIM key of a domain, which need not
exist in mailcow. Success answers `dkim_removed` and `dkim_added`.
Messages: errors `private_key_error`, `dkim_domain_or_sel_exists`.
operationId: importDkimKey
tags:
- DKIM
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- domain
- private_key_file
properties:
domain:
type: string
description: Domain name
dkim_selector:
type: string
default: dkim
description: Selector (letters, digits, `-`, `_`, `.`)
private_key_file:
type: string
description: The private key in PEM format (the text, not a file upload)
overwrite_existing:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: Replace an existing key of the domain
example:
domain: example.org
dkim_selector: dkim2026
private_key_file: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASC...\n-----END PRIVATE KEY-----"
overwrite_existing: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/domain-admin/all:
get:
summary: Get domain administrators
description: Lists all domain administrators.
operationId: getDomainAdmins
tags:
- Domain admin
responses:
"200":
description: The domain administrators, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/DomainAdmin"
example:
- username: domainadmin1
tfa_active: 0
tfa_active_int: 0
active: 1
active_int: 1
created: "2026-09-21 10:24:48"
attributes:
force_tfa: "0"
force_pw_update: "0"
selected_domains:
- example.org
unselected_domains:
- example.com
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/domain-admin/{username}:
get:
summary: Get domain administrator
description: Details of one domain administrator.
operationId: getDomainAdmin
tags:
- Domain admin
parameters:
- name: username
in: path
required: true
description: Username of the domain administrator
schema:
type: string
example: domainadmin1
responses:
"200":
description: The domain administrator, `{}` if there is none of this name
content:
application/json:
schema:
$ref: "#/components/schemas/DomainAdmin"
example:
username: domainadmin1
tfa_active: 0
tfa_active_int: 0
active: 1
active_int: 1
created: "2026-09-21 10:24:48"
attributes:
force_tfa: "0"
force_pw_update: "0"
selected_domains:
- example.org
- example.com
unselected_domains: ""
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/domain/{id}:
get:
summary: Get domains
description: >-
`all` lists all domains (`{}` if none), a domain name returns that
domain, an alias domain name its target. Domain admins see only their
domains. Quotas are in bytes.
operationId: getDomains
tags:
- Domains
parameters:
- name: id
in: path
required: true
description: "`all` or a domain name"
schema:
type: string
example: all
- name: tags
in: query
required: false
description: >-
Only with `all`: comma-separated tag names, answers only the domains
with a tag that contains one of them
schema:
type: string
example: customer,premium
responses:
"200":
description: The list of domains (`all`) or one domain
content:
application/json:
schema:
oneOf:
- type: array
items:
$ref: "#/components/schemas/Domain"
- $ref: "#/components/schemas/Domain"
example:
- max_new_mailbox_quota: 10632560640
def_new_mailbox_quota: 3221225472
quota_used_in_domain: "104857600"
bytes_total: "79324302"
msgs_total: "132"
mboxes_in_domain: 3
mboxes_left: 7
domain_name: example.org
domain_h_name: example.org
description: Example Org
max_num_aliases_for_domain: 400
max_num_mboxes_for_domain: 10
def_quota_for_mbox: 3221225472
max_quota_for_mbox: 10737418240
max_quota_for_domain: 10737418240
relayhost: "0"
backupmx: 0
backupmx_int: 0
gal: 1
gal_int: 1
rl:
value: "100"
frame: h
active: 1
active_int: 1
relay_all_recipients: 0
relay_all_recipients_int: 0
relay_unknown_only: 0
relay_unknown_only_int: 0
created: "2026-09-21 10:24:34"
modified: "2026-11-06 18:15:08"
aliases_in_domain: 1
aliases_left: 399
domain_admins: anna.admin
tags:
- customer
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/domain/template/{id}:
get:
summary: Get domain templates
description: >-
`all` lists the domain templates, an ID returns that template. Domain
admins may call it too. Quotas are in bytes.
operationId: getDomainTemplates
tags:
- Domains
parameters:
- name: id
in: path
required: true
description: "`all` or a template ID"
schema:
type: string
example: all
responses:
"200":
description: The list of templates (`all`) or one template
content:
application/json:
schema:
oneOf:
- type: array
items:
$ref: "#/components/schemas/DomainTemplate"
- $ref: "#/components/schemas/DomainTemplate"
example:
- id: 1
template: Default
type: domain
attributes:
tags: []
max_num_aliases_for_domain: 400
max_num_mboxes_for_domain: 10
def_quota_for_mbox: 3221225472
max_quota_for_mbox: 10737418240
max_quota_for_domain: 10737418240
rl_frame: s
rl_value: ""
active: 1
gal: 1
backupmx: 0
relay_all_recipients: 0
relay_unknown_only: 0
dkim_selector: dkim
key_size: 2048
created: "2026-09-21 10:23:08"
modified: null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/add/domain/template:
post:
summary: Add a domain template
description: >-
Adds a domain template (defaults for new domains). Quotas are sent in
MiB, returned in bytes. Fields not sent, and numbers and quotas sent as
0, get the defaults shown.
Messages: `template_added`; errors `template_name_invalid`,
`template_exists`.
operationId: addDomainTemplate
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/DomainTemplateInput"
- required:
- template
example:
template: Small business
max_num_aliases_for_domain: 400
max_num_mboxes_for_domain: 25
def_quota_for_mbox: 2048
max_quota_for_mbox: 5120
max_quota_for_domain: 51200
rl_value: 500
rl_frame: h
active: 1
gal: 1
backupmx: 0
relay_all_recipients: 0
relay_unknown_only: 0
dkim_selector: dkim
key_size: 2048
tags:
- small
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/domain/template:
post:
summary: Edit domain templates
description: >-
Replaces domain templates. Fields not sent are reset: numbers and quotas
to 0, the rest to the defaults shown. Edit one template per call, with
several IDs all get the first one's name. Always answers
`template_modified`, also for unknown IDs.
operationId: editDomainTemplate
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Template ID or list of template IDs
oneOf:
- type: [integer, string]
- type: array
items:
type: [integer, string]
attr:
$ref: "#/components/schemas/DomainTemplateInput"
example:
items:
- 2
attr:
template: Small business
max_num_aliases_for_domain: 400
max_num_mboxes_for_domain: 50
def_quota_for_mbox: 2048
max_quota_for_mbox: 5120
max_quota_for_domain: 102400
rl_value: 500
rl_frame: h
active: 1
gal: 1
backupmx: 0
relay_all_recipients: 0
relay_unknown_only: 0
dkim_selector: dkim
key_size: 2048
tags:
- small
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/domain/template:
post:
summary: Delete a domain template
description: >-
Deletes a domain template; only the first ID of the list is used. The
`Default` template cannot be deleted. Always answers
`template_removed`.
operationId: deleteDomainTemplate
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Template IDs (only the first is used)
items:
type: [integer, string]
example:
- 2
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/search/domain:
post:
summary: Search domains (table of the UI)
description: >-
Paging, sorting and searching for the DataTables domain table of the UI.
Read-only API keys may use it, domain admins see only their domains.
Positions in `columns` and `order[].column`: 2 domain name, 3 aliases,
4 mailboxes, 5 domain quota, 6 storage (sort only), 7 default mailbox
quota, 8 max. mailbox quota, 10 relay domain, 14 tags (global search
only), 15 active; others mean the domain name. `columns` is required
with `search.value`.
Without `Content-Type: application/json` all domains are returned. SQL
errors answer `{"error": "..."}` with status 200.
operationId: searchDomains
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DomainSearchRequest"
example:
draw: 1
start: 0
length: 10
search:
value: example
order:
- column: 2
dir: asc
columns:
- data: ""
searchable: false
orderable: false
- data: chkbox
searchable: false
orderable: false
- data: domain_h_name
searchable: true
orderable: true
search:
value: ""
responses:
"200":
description: One page of domains, with the counts DataTables needs
content:
application/json:
schema:
$ref: "#/components/schemas/DomainSearchResult"
example:
draw: 1
recordsTotal: 12
recordsFiltered: 1
data:
- max_new_mailbox_quota: 10632560640
def_new_mailbox_quota: 3221225472
quota_used_in_domain: "104857600"
bytes_total: "79324302"
msgs_total: "132"
mboxes_in_domain: 3
mboxes_left: 7
domain_name: example.org
domain_h_name: example.org
description: Example Org
max_num_aliases_for_domain: 400
max_num_mboxes_for_domain: 10
def_quota_for_mbox: 3221225472
max_quota_for_mbox: 10737418240
max_quota_for_domain: 10737418240
relayhost: "0"
backupmx: 0
backupmx_int: 0
gal: 1
gal_int: 1
rl: false
active: 1
active_int: 1
relay_all_recipients: 0
relay_all_recipients_int: 0
relay_unknown_only: 0
relay_unknown_only_int: 0
created: "2026-09-21 10:24:34"
modified: "2026-11-06 18:15:08"
aliases_in_domain: 1
aliases_left: 399
domain_admins: "-"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/alias-domain/{id}:
get:
summary: Get alias domains
description: >-
`all` lists all alias domains, a name returns that alias domain. Domain
admins see only those of their domains.
operationId: getAliasDomains
tags:
- Domains
parameters:
- name: id
in: path
required: true
description: "`all` or an alias domain name"
schema:
type: string
example: all
responses:
"200":
description: The list of alias domains (`all`) or one alias domain
content:
application/json:
schema:
oneOf:
- type: array
items:
$ref: "#/components/schemas/AliasDomain"
- $ref: "#/components/schemas/AliasDomain"
example:
- alias_domain: example.net
parent_is_backupmx: 0
target_domain: example.org
active: 1
active_int: 1
rl: false
created: "2026-10-02 08:12:45"
modified: null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/add/alias-domain:
post:
summary: Add alias domains
description: >-
Adds alias domains: mail goes to the same local part in the target
domain, which must be accessible and no relay domain. Needs the ACL
`alias_domains`. Can also set the rate limit and create a DKIM key. An
invalid name ends the call without an answer.
Messages: `aliasd_added`; errors `alias_domain_invalid`,
`targetd_not_found`, `targetd_relay_domain`.
operationId: addAliasDomain
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- alias_domain
- target_domain
properties:
alias_domain:
type: string
description: >-
Alias domain name; several are separated by spaces, commas,
semicolons or line breaks
target_domain:
type: string
description: The domain the alias domain points to
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: Alias domain active (inactive when not sent)
rl_value:
type: [integer, string]
description: Rate limit, messages per `rl_frame`; empty or 0 = none
rl_frame:
type: string
enum: [s, m, h, d]
description: Rate limit time frame
dkim_selector:
type: string
description: Selector of the DKIM key that is created
key_size:
type: [integer, string]
description: >-
RSA size of the new DKIM key in bits; a key needs
`key_size` and `dkim_selector`
example:
alias_domain: example.net
target_domain: example.org
active: 1
rl_value: 100
rl_frame: h
dkim_selector: dkim
key_size: 2048
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/alias-domain:
post:
summary: Edit alias domains
description: >-
Changes alias domains; fields not sent keep their value. The new target
must be an accessible domain, not an alias domain.
Messages: `aliasd_modified`; errors `alias_domain_invalid`,
`target_domain_invalid`.
operationId: editAliasDomain
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Alias domain name or list of alias domain names
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
properties:
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Alias domain active
target_domain:
type: string
description: New target domain
example:
items:
- example.net
attr:
active: 1
target_domain: example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/alias-domain:
post:
summary: Delete alias domains
description: >-
Deletes alias domains with their aliases, spam aliases and BCC maps.
The rate limit is kept.
Messages: `alias_domain_removed`; error `domain_invalid`.
operationId: deleteAliasDomain
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Alias domain names
items:
type: string
example:
- example.net
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/mta-sts:
post:
summary: Add an MTA-STS policy
description: >-
Adds the MTA-STS policy of a domain, published when active at
`https://mta-sts.<domain>/.well-known/mta-sts.txt`. The `_mta-sts` TXT
record ID is the change time (`YYYYMMDDhhmmss`). Policies of alias
domains are never published, they use their target's. A second policy
fails with a database error. There is no read route.
Messages: errors `version_invalid`, `mode_invalid`, `max_age_invalid`,
`mx_invalid`.
operationId: addMtaSts
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- domain
- version
- mode
- mx
- max_age
properties:
domain:
type: string
description: Domain or alias domain
version:
type: string
enum: [stsv1, STSv1]
description: Policy version (case-insensitive)
mode:
type: string
enum: [enforce, testing, none]
description: >-
`enforce` rejects delivery without valid TLS, `testing`
only reports, `none` publishes without effect
mx:
type: string
description: Comma-separated MX host names, wildcards like `*.example.org` allowed
max_age:
type: [integer, string]
description: Seconds senders may cache the policy, 1 to 31536000
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: Policy published (inactive when not sent)
example:
domain: example.org
version: stsv1
mode: enforce
mx: mail.example.org,mx2.example.org
max_age: 86400
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/mta-sts:
post:
summary: Edit MTA-STS policies
description: >-
Changes MTA-STS policies; fields not sent keep their value, but
`version` is required. Changing `version`, `mode`, `mx` or `max_age`
gives a new policy ID. A domain without policy answers `access_denied`.
Messages: `object_modified`; errors `version_invalid`, `mode_invalid`,
`mx_invalid`.
operationId: editMtaSts
tags:
- Domains
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Domain name or list of domain names
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
required:
- version
properties:
version:
type: string
enum: [stsv1, STSv1]
description: Policy version
mode:
type: string
enum: [enforce, testing, none]
description: Policy mode
mx:
type: string
description: Comma-separated MX host names
max_age:
type: [integer, string]
description: Seconds senders may cache the policy, 1 to 31557600
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
description: Policy published
example:
items:
- example.org
attr:
version: stsv1
mode: testing
mx: mail.example.org
max_age: 604800
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/fail2ban:
get:
summary: Get Fail2Ban settings and bans
description: >-
Returns the Fail2Ban settings, regex filters, allow- and denylists and
the current bans.
operationId: getFail2Ban
tags:
- Fail2Ban
responses:
"200":
description: Settings and bans
content:
application/json:
schema:
$ref: "#/components/schemas/Fail2Ban"
example:
ban_time: 1800
ban_time_increment: true
max_ban_time: 86400
netban_ipv4: 32
netban_ipv6: 128
max_attempts: 10
retry_window: 600
banlist_id: a2c11baf-5770-47de-9c5e-575bd7bc9218
manage_external: 0
regex:
"1": "^mailcow UI: Invalid password for .+ by ([0-9a-f\\.:]+)$"
"2": "^Rspamd UI: Invalid password by ([0-9a-f\\.:]+)$"
whitelist: |-
192.0.2.0/24
mail.example.org
blacklist: 198.51.100.66/32
perm_bans:
- network: 198.51.100.66/32
ip: 198.51.100.66
active_bans:
- queued_for_unban: 0
network: 203.0.113.7/32
ip: 203.0.113.7
banned_until: 00h 27m 08s
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/fail2ban/banlist:
post:
summary: Renew the Fail2Ban banlist URL
description: >-
Gives the banlist URL `/f2b-banlist?id=<banlist_id>` a new random ID;
the old URL stops working. `items` must hold the current `banlist_id`,
else the status is 404. A Redis error gives status 500.
Messages: `f2b_banlist_refreshed`; errors `redis_error`.
operationId: refreshFail2BanBanlist
tags:
- Fail2Ban
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: The current banlist ID (single value or a list with it as first element)
oneOf:
- type: array
items:
type: string
- type: string
attr:
type: object
description: Not used
required:
- items
example:
items:
- a2c11baf-5770-47de-9c5e-575bd7bc9218
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"404":
description: "`items` does not hold the current banlist ID"
content:
application/json:
schema:
$ref: "#/components/schemas/TaskResult"
example:
type: error
msg: Cannot edit item
/api/v1/get/logs/acme/{count}:
get:
summary: Get ACME logs (count or range)
description: Entries of the ACME (Let's Encrypt) log, newest first.
operationId: getAcmeLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/AcmeLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/api/{count}:
get:
summary: Get API logs (count or range)
description: API requests with their data (secrets replaced by `*`), newest first.
operationId: getApiLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/ApiLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/autodiscover/{count}:
get:
summary: Get Autodiscover logs (count or range)
description: Autodiscover requests (Outlook, ActiveSync) with the offered service, newest first.
operationId: getAutodiscoverLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/AutodiscoverLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/dovecot/{count}:
get:
summary: Get Dovecot logs (count or range)
description: Entries of the Dovecot log (IMAP, POP3, Sieve, LMTP), newest first.
operationId: getDovecotLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/DovecotLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/netfilter/{count}:
get:
summary: Get netfilter logs (count or range)
description: Entries of netfilter (failed logins, bans), newest first.
operationId: getNetfilterLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/NetfilterLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/postfix/{count}:
get:
summary: Get Postfix logs (count or range)
description: Entries of the Postfix log (SMTP), newest first.
operationId: getPostfixLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/PostfixLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/ratelimited/{count}:
get:
summary: Get rate limit logs (count or range)
description: Messages rejected by a rate limit, newest first.
operationId: getRatelimitLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/RatelimitLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/rspamd-history/{count}:
get:
summary: Get Rspamd history (count or range)
description: Messages scanned by Rspamd, newest first.
operationId: getRspamdHistoryByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: >-
`N`: the newest N messages; `from-to` (from ≥ 1) counts from 0, so
`2-3` gives the third and fourth newest
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/RspamdHistory"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/sogo/{count}:
get:
summary: Get SOGo logs (count or range)
description: Entries of the SOGo log, newest first.
operationId: getSogoLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/SogoLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/watchdog/{count}:
get:
summary: Get watchdog logs (count or range)
description: Watchdog health checks, newest first.
operationId: getWatchdogLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/WatchdogLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/acme:
get:
summary: Get ACME logs
description: The newest 1000 entries of the ACME (Let's Encrypt) log, newest first.
operationId: getAcmeLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/AcmeLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/api:
get:
summary: Get API logs
description: >-
The newest 1000 API requests with their data (secrets replaced by
`*`), newest first.
operationId: getApiLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/ApiLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/autodiscover:
get:
summary: Get Autodiscover logs
description: >-
The newest 1000 Autodiscover requests (Outlook, ActiveSync) with the
offered service, newest first.
operationId: getAutodiscoverLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/AutodiscoverLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/cron:
get:
summary: Get cron logs
description: >-
The newest 1000 entries of the mailcow scheduled tasks (identity
provider sync, group shares, ...), newest first.
operationId: getCronLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/CronLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/cron/{count}:
get:
summary: Get cron logs (count or range)
description: Entries of the mailcow scheduled tasks, newest first.
operationId: getCronLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: "`N`: the newest N entries; `from-to`: entries `from` to `to` (newest = 1)"
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/CronLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/dovecot:
get:
summary: Get Dovecot logs
description: The newest 1000 entries of the Dovecot log (IMAP, POP3, Sieve, LMTP), newest first.
operationId: getDovecotLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/DovecotLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/netfilter:
get:
summary: Get netfilter logs
description: The newest 1000 entries of netfilter (failed logins, bans), newest first.
operationId: getNetfilterLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/NetfilterLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/postfix:
get:
summary: Get Postfix logs
description: The newest 1000 entries of the Postfix log (SMTP), newest first.
operationId: getPostfixLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/PostfixLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/ratelimited:
get:
summary: Get rate limit logs
description: The newest 1000 messages rejected by a rate limit, newest first.
operationId: getRatelimitLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/RatelimitLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/rspamd-history:
get:
summary: Get Rspamd history
description: The newest 1000 messages scanned by Rspamd, newest first.
operationId: getRspamdHistory
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/RspamdHistory"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/rspamd-stats:
get:
summary: Get Rspamd statistics
description: Rspamd statistics (scanned and learned messages, actions, Bayes).
operationId: getRspamdStats
tags:
- Logs
responses:
"200":
description: The statistics, `{}` if Rspamd cannot be reached
content:
application/json:
schema:
$ref: "#/components/schemas/RspamdStats"
example:
version: 3.12.1
config_id: ch8ha1o68oxb3xf9izngisz4wxuxgs86n9gg6yko7jtt4msu4bxhuunnoi4pk7an4y5htzjb1y9nwsxmkjhdu671ocb5b5ea1g38csb
uptime: 25891
read_only: false
scanned: 300
learned: 30
actions:
reject: 38
soft reject: 0
rewrite subject: 0
add header: 6
greylist: 1
no action: 255
scan_times:
- 0.340365
- 0.48114
spam_count: 44
ham_count: 256
connections: 24
control_connections: 700
total_learns: 29
statfiles:
- revision: 6
users: 1
used: 0
total: 0
size: 0
symbol: BAYES_SPAM
type: redis
languages: 0
class: spam
fuzzy_hashes:
mailcow: 0
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/sasl:
get:
summary: Get SASL logs
description: >-
The newest 1000 successful logins (IMAP, POP3, SMTP, SOGo, ...), one
entry per service, address and user, newest first.
operationId: getSaslLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/SaslLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/sasl/{count}:
get:
summary: Get SASL logs (count or range)
description: >-
Successful logins, one entry per service, address and user, newest
first.
operationId: getSaslLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: >-
`N`: the newest N entries; `from-to`: `to` entries starting at
`from` (newest = 1), so `2-3` gives entries 2 to 4
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/SaslLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/sogo:
get:
summary: Get SOGo logs
description: The newest 1000 entries of the SOGo log, newest first.
operationId: getSogoLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/SogoLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/ui:
get:
summary: Get mailcow UI logs
description: The newest 1000 messages of UI and API calls, newest first.
operationId: getUiLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/UiLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/ui/{count}:
get:
summary: Get mailcow UI logs (count or range)
description: Messages of UI and API calls, newest first.
operationId: getUiLogsByCount
tags:
- Logs
parameters:
- name: count
in: path
required: true
description: >-
`N`: the newest N entries; `from-to`: `to` entries starting at
`from` (newest = 1), so `2-3` gives entries 2 to 4
schema:
type: string
pattern: ^[0-9]+(-[0-9]+)?$
example: "50"
responses:
"200":
$ref: "#/components/responses/UiLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/logs/watchdog:
get:
summary: Get watchdog logs
description: The newest 1000 watchdog health checks, newest first.
operationId: getWatchdogLogs
tags:
- Logs
responses:
"200":
$ref: "#/components/responses/WatchdogLogs"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox/{id}:
get:
tags:
- Mailboxes
summary: Get a mailbox
operationId: getMailbox
description: >-
One mailbox, `{}` if not found or no access. A mailbox user may read
its own.
With `tags`, `{id}` is a search term: the answer lists the mailboxes
whose address contains `{id}` and that have a matching tag.
parameters:
- name: id
in: path
required: true
description: "Mailbox address (with `tags`: part of the address, e.g. a domain)"
schema:
type: string
example: john.doe@example.org
- $ref: "#/components/parameters/MailboxTagsQuery"
responses:
"200":
description: The mailbox; with `tags` a list of mailboxes
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/Mailbox"
- type: array
items:
$ref: "#/components/schemas/Mailbox"
examples:
mailbox:
$ref: "#/components/examples/MailboxDetails"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox-group/{id}:
get:
summary: Get mailbox group
description: >-
One group by id, visible as in `GET /api/v1/get/mailbox-group/all`.
operationId: getMailboxGroup
tags:
- Groups
parameters:
- name: id
in: path
required: true
description: Group id
schema:
type: integer
example: 7
responses:
"200":
description: The group
content:
application/json:
schema:
$ref: "#/components/schemas/MailboxGroup"
example:
id: 7
domain: example.org
name: Sales
description: Sales team
address: sales@example.org
sender_allowed: 1
sogo_visible: 0
internal: 1
template_id: 3
template: Staff
priority: 10
idp_ref: null
members:
- username: alice@example.org
source: manual
send_as:
- "@example.com"
imap_grants: []
sogo_grants: []
active: 1
created: "2026-10-25 12:00:00"
modified: null
can_edit: true
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox-group/member/{username}:
get:
summary: Get group memberships of a mailbox
description: >-
The groups of a mailbox with its effective template and send-as
addresses. Domain admins with the `mailbox_groups` ACL may read their
mailboxes and see only groups of their domains; users may read their
own.
operationId: getMailboxGroupMemberships
tags:
- Groups
parameters:
- name: username
in: path
required: true
description: Mailbox (case-insensitive)
schema:
type: string
example: alice@example.org
responses:
"200":
description: The memberships
content:
application/json:
schema:
$ref: "#/components/schemas/MailboxGroupMemberships"
example:
groups:
- id: 7
domain: example.org
name: Sales
address: sales@example.org
sender_allowed: 1
active: 1
priority: 10
template: Staff
source: manual
template: Staff
send_as:
- orders@example.org
- sales@example.org
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox-group/all:
get:
summary: Get mailbox groups
description: >-
All groups the caller may see, ordered by domain and name. Domain admins
with the `mailbox_groups` ACL get the groups of their domains.
operationId: getMailboxGroups
tags:
- Groups
responses:
"200":
description: The groups
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/MailboxGroup"
example:
- id: 7
domain: example.org
name: Sales
description: Sales team
address: sales@example.org
sender_allowed: 1
sogo_visible: 0
internal: 0
template_id: 3
template: Staff
priority: 10
idp_ref: null
members:
- username: alice@example.org
source: manual
- username: bob@example.org
source: idp
send_as:
- orders@example.org
imap_grants:
- owner: shared@example.org
rights: write
subscribe: 1
state: applied
last_error: null
sogo_grants:
- owner: shared@example.org
type: Calendar
folder: personal
access: read
subscribe: 0
state: pending
last_error: null
active: 1
created: "2026-10-25 12:00:00"
modified: "2026-10-28 09:14:03"
can_edit: true
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox-group/all/{domains}:
get:
summary: Get mailbox groups of domains
description: >-
Like `GET /api/v1/get/mailbox-group/all`, limited to the given domains.
operationId: getMailboxGroupsOfDomains
tags:
- Groups
parameters:
- name: domains
in: path
required: true
description: One domain or a comma-separated list of domains
schema:
type: string
example: example.org,example.com
responses:
"200":
description: The groups of the domains
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/MailboxGroup"
example:
- id: 7
domain: example.org
name: Sales
description: ""
address: sales@example.org
sender_allowed: 1
sogo_visible: 1
internal: 0
template_id: null
template: null
priority: 0
idp_ref: null
members:
- username: alice@example.org
source: manual
send_as: []
imap_grants: []
sogo_grants: []
active: 1
created: "2026-10-25 12:00:00"
modified: null
can_edit: true
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/identity-provider/sync-status:
get:
summary: Get identity sync status
description: >-
Status of the identity sync: provider, mailbox counts and the last 10
runs. Runs with status `blocked` (stopped by `offboarding_limit`) or
`error` changed nothing.
operationId: getIdentitySyncStatus
tags:
- Identity Provider
responses:
"200":
description: The sync status
content:
application/json:
schema:
$ref: "#/components/schemas/IdentitySyncStatus"
example:
provider: keycloak
can_sync: true
sync_enabled: true
counts:
accounts: 120
linked: 118
idp_disabled: 2
missing: 1
runs:
- id: 42
provider: keycloak
mode: run
status: ok
requested_by: ""
created: "2026-11-09 12:00:00"
started: "2026-11-09 12:00:01"
finished: "2026-11-09 12:00:03"
summary:
counts:
links: 0
creates: 1
deactivate: 1
restore: 0
release: 0
missing: 1
found: 0
updates: 3
group_creates: 0
group_renames: 0
memberships: 2
orphaned_groups: 0
conflicts: 0
membership_removals: 0
skipped: 0
errors: 0
details:
creates:
- new.user@example.org
deactivate:
- left.user@example.org
restore: []
missing:
- left.user@example.org
group_creates: []
conflicts: []
blocked: false
errors: []
mode: run
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/identity-link/{username}:
get:
summary: Get identity link of a mailbox
description: >-
The Identity Provider user a mailbox is linked to. Domain admins may
read their mailboxes. A never linked mailbox that the sync misses at the
provider has `missing_since` but no `external_id`.
operationId: getIdentityLink
tags:
- Identity Provider
parameters:
- name: username
in: path
required: true
description: Mailbox (case-insensitive)
schema:
type: string
example: alice@example.org
responses:
"200":
description: The link
content:
application/json:
schema:
$ref: "#/components/schemas/IdentityLink"
example:
provider: keycloak
external_id: 8d5da28d-7541-428b-8356-a9704f73e7f4
idp_disabled: 0
missing_since: null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailq/all:
get:
summary: Get the mail queue
description: >-
Returns the Postfix mail queue, at most 10000 entries.
operationId: getMailQueue
tags:
- Queue Manager
responses:
"200":
description: List of queued messages
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/MailQueueItem"
example:
- queue_name: deferred
queue_id: B98C6260CA1
arrival_time: 1762768034
message_size: 1848
forced_expire: false
sender: sender@example.org
recipients:
- "rcpt@example.com (connect to mx.example.com[192.0.2.25]:25: Connection timed out)"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/postcat/{qid}:
get:
summary: Get a queued message
description: >-
Returns a queued message as postcat prints it: envelope, headers and
body. The answer is plain text despite the JSON content type. An
unknown queue ID gives the error text of postcat.
operationId: getQueuedMessage
tags:
- Queue Manager
parameters:
- name: qid
in: path
required: true
description: Postfix queue ID
schema:
type: string
example: B98C6260CA1
responses:
"200":
description: The postcat output as plain text (despite the JSON content type)
content:
application/json:
schema:
type: string
example: |
*** ENVELOPE RECORDS deferred/B/B98C6260CA1 ***
message_size: 1848 612 1 0 1848 0
message_arrival_time: Mon Nov 10 09:47:14 2026
create_time: Mon Nov 10 09:47:14 2026
named_attribute: rewrite_context=local
sender: sender@example.org
*** MESSAGE CONTENTS deferred/B/B98C6260CA1 ***
From: Sender <sender@example.org>
To: rcpt@example.com
Subject: Test
Hello
*** HEADER EXTRACTED deferred/B/B98C6260CA1 ***
original_recipient: rcpt@example.com
recipient: rcpt@example.com
*** MESSAGE FILE END deferred/B/B98C6260CA1 ***
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/oauth2-client/{id}:
get:
summary: Get OAuth2 client
description: One OAuth2 client with its secret.
operationId: getOAuth2Client
tags:
- oAuth Clients
parameters:
- name: id
in: path
required: true
description: ID of the client (`id`, not `client_id`)
schema:
type: integer
example: 1
responses:
"200":
description: The client, `{}` if there is none with this ID
content:
application/json:
schema:
$ref: "#/components/schemas/OAuth2Client"
example:
id: 1
client_id: 17c76aaa88c0
client_secret: 73fc668a88147e32a31ff80c
redirect_uri: https://app.example.org/oauth/callback
grant_types: null
scope: profile
user_id: null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/oauth2-client/all:
get:
summary: Get OAuth2 clients
description: >-
Lists the clients of the mailcow OAuth2 server with their secrets.
operationId: getOAuth2Clients
tags:
- oAuth Clients
responses:
"200":
description: The clients, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/OAuth2Client"
example:
- id: 1
client_id: 17c76aaa88c0
client_secret: 73fc668a88147e32a31ff80c
redirect_uri: https://app.example.org/oauth/callback
grant_types: null
scope: profile
user_id: null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/oauth2-client:
post:
summary: Edit OAuth2 clients
description: >-
Per client, `revoke_tokens` deletes its tokens, else `renew_secret`
sets a new secret, else `redirect_uri` is changed. The first two act
whenever present, even with value 0.
Messages: `object_modified`; error `Redirect/Callback URL cannot be
empty`.
operationId: editOAuth2Client
tags:
- oAuth Clients
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
items:
description: ID of the client, or a list of IDs
oneOf:
- type: [integer, string]
- type: array
items:
type: [integer, string]
attr:
type: object
properties:
redirect_uri:
type: string
description: New redirect URL; empty or missing keeps the current one
revoke_tokens:
type: [integer, string, boolean]
description: Present = delete the access and refresh tokens of the client
renew_secret:
type: [integer, string, boolean]
description: Present = generate a new client secret
required:
- items
- attr
example:
items:
- 1
attr:
redirect_uri: https://app.example.org/oauth/callback2
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/policy_bl_domain/{domain}:
get:
summary: Get the sender deny list of a domain
description: >-
The deny list (blacklist) entries of the domain and all its mailboxes;
`object` tells which.
operationId: getDomainBlacklist
tags:
- Domain antispam policies
parameters:
- name: domain
in: path
required: true
description: Domain name
schema:
type: string
example: example.org
responses:
"200":
description: The deny list entries
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/DomainPolicyEntry"
example:
- object: example.org
value: "*@spam.example.com"
prefid: 13
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/policy_wl_domain/{domain}:
get:
summary: Get the sender allow list of a domain
description: >-
The allow list (whitelist) entries of the domain and all its
mailboxes; `object` tells which.
operationId: getDomainWhitelist
tags:
- Domain antispam policies
parameters:
- name: domain
in: path
required: true
description: Domain name
schema:
type: string
example: example.org
responses:
"200":
description: The allow list entries
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/DomainPolicyEntry"
example:
- object: example.org
value: "*@partner.example.com"
prefid: 12
- object: anna@example.org
value: newsletter@example.net
prefid: 15
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/quarantine/all:
get:
summary: Get quarantined messages
description: >-
Returns the quarantined messages without content. Admins get every
item, domain admins those of their domains, mailbox users their own.
operationId: getQuarantine
tags:
- Quarantine
responses:
"200":
description: List of quarantine items
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/QuarantineItem"
example:
- id: 33
qid: 8224615004C1
subject: You have won
virus_flag: 0
score: 15.48
rcpt: john.doe@example.org
sender: bounces@send.example.com
action: reject
created: 1762768034
notified: 1
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/quarantine_category:
post:
tags:
- Quarantine
summary: Set the quarantine notification category of mailboxes
operationId: editQuarantineCategory
description: >-
Which quarantined mail the notifications list: rejected (`reject`),
sent to junk (`add_header`) or both (`all`). Needs the user ACL
`quarantine_category`; a mailbox user may change only its own. An
invalid value answers `access_denied`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
required:
- quarantine_category
properties:
quarantine_category:
type: string
enum:
- reject
- add_header
- all
example:
items:
- john.doe@example.org
attr:
quarantine_category: all
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/quarantine/{id}:
get:
summary: Get a quarantined message
description: >-
Returns one quarantine item with the raw message and the Rspamd
symbols. Domain admins and mailbox users only get their own items.
`[]` for an unknown ID.
operationId: getQuarantineItem
tags:
- Quarantine
parameters:
- name: id
in: path
required: true
description: ID of the quarantine item
schema:
type: string
example: "33"
responses:
"200":
description: The quarantine item
content:
application/json:
schema:
$ref: "#/components/schemas/QuarantineItemDetails"
example:
id: 33
qid: 8224615004C1
subject: You have won
score: 15.48
ip: 198.51.100.23
action: reject
symbols: '[{"name":"BAYES_SPAM","score":5.1,"options":["99.99%"]},{"name":"RBL_SPAMHAUS_SBL","score":4.0}]'
fuzzy_hashes: "[]"
sender: bounces@send.example.com
rcpt: john.doe@example.org
msg: "Return-Path: <bounces@send.example.com>\r\nFrom: Prize <bounces@send.example.com>\r\nTo: john.doe@example.org\r\nSubject: You have won\r\n\r\nClick here\r\n"
domain: null
notified: 1
created: "2026-11-10 09:47:14"
user: unknown
qhash: 3f9d8c0b2a4e6f1d7c5b9a8e0f2d4c6b8a1e3f5d7c9b0a2e4f6d8c1b3a5e7f9d
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/quarantine:
post:
summary: Edit quarantine settings
description: >-
Saves the global quarantine settings. Fields not sent are reset; a
missing `retention_size` or `max_size` turns the quarantine off. The
current values cannot be read through the API.
Messages: `saved_settings`; errors `redis_error`.
operationId: editQuarantineSettings
tags:
- Quarantine
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: Ignored
attr:
type: object
properties:
action:
type: string
const: settings
retention_size:
type: [integer, string]
description: Items kept per mailbox; 0 disables the quarantine
max_size:
type: [integer, string]
description: Maximum size in MiB of a quarantined message; 0 disables the quarantine
max_score:
type: [number, string]
description: No notification for messages with a higher spam score; empty = no limit
max_age:
type: [integer, string]
description: Days an item is kept; 0 or less becomes 365
release_format:
type: string
enum:
- raw
- attachment
default: raw
description: Deliver released messages as they are or as an attachment of a new message
exclude_domains:
type: array
items:
type: string
description: Domains and alias domains whose mail is not quarantined
sender:
type: string
description: Sender of the notifications (invalid address = empty)
subject:
type: string
description: Subject of the notifications
bcc:
type: string
description: Address that gets a copy of every notification (invalid address = empty)
redirect:
type: string
description: Address that gets all notifications instead of the mailboxes (invalid address = empty)
html_tmpl:
type: string
description: HTML template of the notifications (empty = the default template)
required:
- action
required:
- attr
example:
items:
- self
attr:
action: settings
retention_size: "20"
max_size: "15"
max_score: ""
max_age: "365"
release_format: raw
exclude_domains:
- example.com
sender: quarantine@example.org
subject: Spam Quarantine Notification
bcc: ""
redirect: ""
html_tmpl: ""
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/recipient_map/{id}:
get:
tags:
- Address Rewriting
summary: Get recipient maps
operationId: getRecipientMaps
description: >-
`all` lists the recipient maps, an ID returns one map with an extra
member `"0": null`. `{}` if there is none or the caller is no
administrator.
parameters:
- name: id
in: path
required: true
description: "`all` or the ID of a recipient map"
schema:
type: string
example: all
responses:
"200":
description: The list of recipient maps (`all`) or one recipient map
content:
application/json:
schema:
anyOf:
- type: array
items:
$ref: "#/components/schemas/RecipientMap"
- $ref: "#/components/schemas/RecipientMap"
examples:
all:
summary: get/recipient_map/all
value:
- id: 1
recipient_map_old: jane.doe@example.org
recipient_map_new: jane.smith@example.org
active: 1
created: "2026-11-04 08:30:00"
modified: null
- id: 2
recipient_map_old: "@example.net"
recipient_map_new: "@example.org"
active: 0
created: "2026-11-04 08:31:12"
modified: "2026-11-05 17:02:45"
one:
summary: get/recipient_map/1
value:
id: 1
recipient_map_old: jane.doe@example.org
recipient_map_new: jane.smith@example.org
active: 1
created: "2026-11-04 08:30:00"
modified: null
"0": null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/bcc:
post:
tags:
- Address Rewriting
summary: Update BCC maps
operationId: editBccMap
description: >-
Changes the BCC maps in `items`; fields not sent keep their value,
`local_dest` cannot be changed. Same callers as add/bcc. `type` is not
validated: send only `sender` or `rcpt`.
Messages: `bcc_edited`; errors `bcc_must_be_email`, `bcc_exists`.
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: IDs of the BCC maps, a single value or a list
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
attr:
type: object
properties:
bcc_dest:
type: string
description: E-mail address that gets the copies
type:
type: string
enum:
- sender
- rcpt
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
required:
- items
- attr
example:
items:
- 3
attr:
bcc_dest: journal@example.com
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/recipient_map:
post:
tags:
- Address Rewriting
summary: Update recipient maps
operationId: editRecipientMap
description: >-
Changes the recipient maps in `items`; fields not sent keep their
value. `recipient_map_entry_exists` stops the call.
Messages: `recipient_map_entry_saved`; errors
`invalid_recipient_map_old`, `invalid_recipient_map_new`.
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: IDs of the recipient maps, a single value or a list
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
attr:
type: object
properties:
recipient_map_old:
type: string
description: Original recipient, an e-mail address or a domain
recipient_map_new:
type: string
description: New recipient, an e-mail address or a domain
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
required:
- items
- attr
example:
items:
- 1
attr:
recipient_map_new: jane.smith@example.org
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/relayhost/{id}:
get:
tags:
- Routing
summary: Get sender-dependent transports
operationId: getRelayhosts
description: >-
`all` lists the sender-dependent transports, an ID returns one; the
password is in clear text. `{}` if there is none or the caller is no
administrator.
parameters:
- name: id
in: path
required: true
description: "`all` or the ID of a sender-dependent transport"
schema:
type: string
example: all
responses:
"200":
description: The list of sender-dependent transports (`all`) or one entry
content:
application/json:
schema:
anyOf:
- type: array
items:
$ref: "#/components/schemas/Relayhost"
- $ref: "#/components/schemas/Relayhost"
examples:
all:
summary: get/relayhost/all
value:
- id: 1
hostname: "[smtp.example.com]:587"
username: relay-user@example.com
password: Secret-Passphrase-42
active: 1
password_short: Sec...
used_by_domains: example.org, example.net
used_by_mailboxes: anna@example.com
one:
summary: get/relayhost/1
value:
id: 1
hostname: "[smtp.example.com]:587"
username: relay-user@example.com
password: Secret-Passphrase-42
active: 1
password_short: Sec...
used_by_domains: example.org, example.net
used_by_mailboxes: anna@example.com
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/resource/all:
get:
tags:
- Resources
summary: Get all resources
operationId: getResources
description: >-
All resources of the domains the caller manages, `{}` if none.
responses:
"200":
description: List of resources
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Resource"
example:
- name: MeetingRoom1@example.org
kind: location
multiple_bookings: 0
description: Meeting Room 1
active: 1
active_int: 1
domain: example.org
local_part: MeetingRoom1
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/resource/{id}:
get:
tags:
- Resources
summary: Get a resource
operationId: getResource
description: >-
One resource by address, `{}` if not found or no access.
parameters:
- name: id
in: path
required: true
description: Address of the resource
schema:
type: string
example: MeetingRoom1@example.org
responses:
"200":
description: The resource
content:
application/json:
schema:
$ref: "#/components/schemas/Resource"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/resource:
post:
tags:
- Resources
summary: Update resources
operationId: editResource
description: >-
Changes resources, also for domain admins; fields not sent keep their
value. The address does not change with the description.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Resource address or list of addresses
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
properties:
description:
type: string
description: Name shown in SOGo
kind:
type: string
enum:
- location
- group
- thing
multiple_bookings:
type: [integer, string]
description: 0 always free, -1 unlimited but busy when booked, n ≥ 1 at most n overlapping bookings
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
example:
items:
- MeetingRoom1@example.org
attr:
description: Meeting Room 1 (2nd floor)
multiple_bookings: -1
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/rl-mbox/{mailbox}:
get:
tags:
- Ratelimits
summary: Get the rate limit of a mailbox
operationId: getMailboxRatelimit
description: >-
The rate limit set on the mailbox; `{}` if it has none (the domain
limit applies) or no access.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: The rate limit
content:
application/json:
schema:
$ref: "#/components/schemas/MailboxRatelimit"
example:
value: "100"
frame: h
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/rl-domain/{domain}:
get:
summary: Get rate limits of domains
description: >-
Rate limit (outgoing messages per time frame) of a domain or alias
domain; `all` lists all that have one.
operationId: getDomainRatelimits
tags:
- Ratelimits
parameters:
- name: domain
in: path
required: true
description: "`all` or a domain or alias domain name"
schema:
type: string
example: example.org
responses:
"200":
description: The rate limit, or the list of rate limits (`all`)
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/DomainRatelimit"
- type: array
items:
allOf:
- $ref: "#/components/schemas/DomainRatelimit"
- type: object
properties:
domain:
type: string
description: Domain or alias domain
example:
value: "100"
frame: h
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/rl-domain:
post:
summary: Set rate limits of domains
description: >-
Sets the rate limit of domains or alias domains. Needs the ACL
`ratelimit`. `rl_frame` is required also when removing the limit.
Messages: `rl_saved`; error `rl_timeframe`.
operationId: editDomainRatelimits
tags:
- Ratelimits
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Domain or alias domain name, or a list of them
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
required:
- rl_frame
properties:
rl_value:
type: [integer, string]
description: Messages per `rl_frame`; empty or 0 removes the limit
rl_frame:
type: string
enum: [s, m, h, d]
description: Time frame (second, minute, hour, day)
example:
items:
- example.org
attr:
rl_value: 100
rl_frame: h
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/rl-mbox/all:
get:
tags:
- Ratelimits
summary: Get the rate limits of all mailboxes
operationId: getMailboxRatelimits
description: >-
The rate limits set on single mailboxes the caller manages (no domain
limits). `{}` if none.
responses:
"200":
description: List of rate limits
content:
application/json:
schema:
type: array
items:
allOf:
- $ref: "#/components/schemas/MailboxRatelimit"
- type: object
properties:
mailbox:
type: string
example:
- value: "100"
frame: h
mailbox: john.doe@example.org
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/rl-mbox:
post:
tags:
- Ratelimits
summary: Set the rate limit of mailboxes
operationId: editMailboxRatelimit
description: >-
Sets the rate limit of mailboxes: `rl_value` messages per `rl_frame`. 0
or empty removes it, but `rl_frame` must still be valid. Domain admins
need the ACL `ratelimit`. Answers `rl_saved` or `rl_timeframe`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
required:
- rl_frame
properties:
rl_value:
type: [integer, string]
description: Number of messages, 0 or empty removes the limit
rl_frame:
type: string
enum:
- s
- m
- h
- d
description: Per second, minute, hour or day
example:
items:
- john.doe@example.org
attr:
rl_value: 100
rl_frame: h
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/rlhash:
post:
tags:
- Ratelimits
summary: Reset a rate limit counter
operationId: deleteRatelimitHash
description: >-
Resets the counter of a rate-limited sender (`rl_hash` from
`get/logs/ratelimited`) so it can send again. Send one hash. Answers
`1` (not JSON) when deleted, else an empty body.
requestBody:
required: true
content:
application/json:
schema:
type: array
description: The hash
items:
type: string
pattern: "^RL[0-9A-Za-z=]+$"
example:
- RLkfx5cv4sq1i3ehpkz5bgdhcq9u9gkzj
responses:
"200":
description: "`1` if deleted, else an empty body"
content:
application/json:
schema:
type: integer
const: 1
example: 1
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/status/containers:
get:
summary: Get container status
description: State, start time and image of all mailcow containers (also stopped ones).
operationId: getContainerStatus
tags:
- Status
responses:
"200":
description: The containers, `null` if dockerapi cannot be reached
content:
application/json:
schema:
type: object
additionalProperties:
$ref: "#/components/schemas/ContainerStatus"
example:
dovecot-mailcow:
type: info
container: dovecot-mailcow
state: running
started_at: "2026-11-10T11:00:51.541059812Z"
image: ghcr.io/mailcow/dovecot:2.3.21.1-4
postfix-mailcow:
type: info
container: postfix-mailcow
state: running
started_at: "2026-11-10T11:00:51.292779901Z"
image: ghcr.io/mailcow/postfix:1.80
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/status/vmail:
get:
summary: Get mail storage status
description: Disk usage of the file system that holds the mail storage.
operationId: getVmailStatus
tags:
- Status
responses:
"200":
description: The disk usage (`df -H` values)
content:
application/json:
schema:
type: object
properties:
type:
type: string
const: info
disk:
type: string
description: Device
used:
type: string
description: Used space
total:
type: string
description: Size of the file system
used_percent:
type: string
description: Used space in percent
example:
type: info
disk: /dev/sda1
used: 65G
total: 105G
used_percent: 66%
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/status/version:
get:
summary: Get mailcow version
description: The installed mailcow version, the release tag on master, else the short commit ID.
operationId: getVersion
tags:
- Status
responses:
"200":
description: The version
content:
application/json:
schema:
type: object
properties:
version:
type: [string, "null"]
description: Release tag or commit ID
example:
version: "2026-11"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/status/container/{id}:
get:
summary: Get container statistics
description: >-
Up to three Docker stats snapshots of one container, about five
seconds apart. Needs the full container ID, which the API does not
list; an unknown ID answers after 60 seconds with an error string.
operationId: getContainerStats
tags:
- Status
parameters:
- name: id
in: path
required: true
description: Full Docker container ID
schema:
type: string
example: 5d0f3cbb2a6e4f6c8e0e1c3b9a7d2f41b6c5e8a9d0f1e2c3b4a5968778695a4b
responses:
"200":
description: >-
Docker stats objects (see the Docker Engine API, `ContainerStats`),
oldest first; `false` without ID
content:
application/json:
schema:
type: array
items:
type: object
description: One Docker stats snapshot
properties:
read:
type: string
description: Time of the snapshot
name:
type: string
id:
type: string
cpu_stats:
type: object
precpu_stats:
type: object
memory_stats:
type: object
blkio_stats:
type: object
networks:
type: object
pids_stats:
type: object
additionalProperties: true
example:
- read: "2026-11-10T19:20:01.123456789Z"
name: /mailcowdockerized-dovecot-mailcow-1
id: 5d0f3cbb2a6e4f6c8e0e1c3b9a7d2f41b6c5e8a9d0f1e2c3b4a5968778695a4b
pids_stats:
current: 38
memory_stats:
usage: 104857600
limit: 12541669376
blkio_stats:
io_service_bytes_recursive:
- major: 8
minor: 0
op: read
value: 1052672
- major: 8
minor: 0
op: write
value: 40960
networks:
eth0:
rx_bytes: 2621440
tx_bytes: 1048576
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/status/host:
get:
summary: Get host statistics
description: CPU, memory, uptime and architecture of the Docker host.
operationId: getHostStatus
tags:
- Status
responses:
"200":
description: The host statistics
content:
application/json:
schema:
$ref: "#/components/schemas/HostStats"
example:
cpu:
cores: 4
usage: 6
memory:
total: 12541669376
usage: 62.5
swap:
- 1022357504
- 512716800
- 509640704
- 50.2
- 1392812032
- 3864260608
uptime: 703800.5492310524
system_time: "10.11.2026 19:13:07"
architecture: x86_64
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/status/host/ip:
get:
summary: Get public IP addresses
description: >-
The public IPv4 and IPv6 address of the server. Asks
ipv4.mailcow.email and ipv6.mailcow.email on every call, even with the
IP check off.
operationId: getHostIps
tags:
- Status
responses:
"200":
description: The addresses, `false` for an address that could not be determined
content:
application/json:
schema:
type: object
properties:
ipv4:
type: [string, boolean]
description: Public IPv4 address
ipv6:
type: [string, boolean]
description: Public IPv6 address
example:
ipv4: 198.51.100.25
ipv6: 2001:db8::25
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/syncjobs/all/no_log:
get:
summary: Get all sync jobs without logs
description: >-
Like `GET /api/v1/get/syncjobs/all`, with an empty `log`.
operationId: getSyncJobsWithoutLog
tags:
- Sync jobs
responses:
"200":
description: The sync jobs
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SyncJob"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/syncjob_source/{id}:
get:
summary: Get sync source
description: >-
One sync source by id, visible as in `GET /api/v1/get/syncjob_source/all`.
operationId: getSyncJobSource
tags:
- Sync jobs
parameters:
- name: id
in: path
required: true
description: Source id
schema:
type: integer
example: 4
responses:
"200":
description: The sync source
content:
application/json:
schema:
$ref: "#/components/schemas/SyncJobSource"
example:
id: 4
name: Google Workspace
description: ""
created_by: admin
scope: all
host1: imap.gmail.com
port1: 993
enc1: SSL
verify_cert: 1
auth_type: XOAUTH2
oauth_flow: authorization_code
oauth_token_endpoint: https://oauth2.googleapis.com/token
oauth_authorize_endpoint: https://accounts.google.com/o/oauth2/v2/auth
oauth_userinfo_endpoint: null
oauth_client_id: 1234567890-example.apps.googleusercontent.com
oauth_scope: https://mail.google.com/ openid email
oauth_extra_params: '{"access_type":"offline","prompt":"consent"}'
oauth_token_expires: null
oauth_last_refresh_error: null
oauth_last_refresh_attempt: null
created: "2026-11-01 10:00:00"
modified: null
active: 1
domains: []
users: []
can_edit: true
host: imap.gmail.com
port: 993
enc: SSL
has_client_secret: true
has_access_token: false
oauth_redirect_uri: https://mail.example.org/syncjob-oauth
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/syncjob_options:
get:
summary: Get allowed custom imapsync options
description: >-
The imapsync options allowed in `custom_params`, with their rule: `true`
needs a value, `false` takes none, a string is a regular expression the
whole value must match. Options that run code, use local files or print
secrets are never allowed. Every logged-in user may read it.
operationId: getSyncJobOptions
tags:
- Sync jobs
responses:
"200":
description: Option name => rule
content:
application/json:
schema:
type: object
additionalProperties:
type:
- boolean
- string
example:
authmd51: false
debugssl: true
folder: true
maxsize: true
syncinternaldates: false
sslargs1: "^SSL_verify_mode=[01]$"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/imapsync_settings:
get:
summary: Get global sync job settings
description: >-
Settings of the sync job runner.
operationId: getSyncJobSettings
tags:
- Sync jobs
responses:
"200":
description: The settings
content:
application/json:
schema:
$ref: "#/components/schemas/SyncJobSettings"
example:
max_parallel: 3
max_bytes_per_second: 2048000
max_kb_per_second: 2000
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/syncjobs/all:
get:
summary: Get all sync jobs
description: >-
All sync jobs with their logs, in queue order. Admins also get jobs of
deleted mailboxes, domain admins the jobs of their mailboxes; users get
none, see `GET /api/v1/get/syncjobs/{mailbox}`.
operationId: getSyncJobs
tags:
- Sync jobs
responses:
"200":
description: The sync jobs
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SyncJob"
example:
- id: 12
user2: alice@example.org
regextrans2: ""
authmd51: 0
domain2: ""
subfolder2: Imported
user1: alice@old-provider.example.com
exclude: "(?i)spam|(?i)junk"
maxage: 0
mins_interval: 20
maxbytespersecond: "0"
delete2duplicates: 1
delete1: 0
delete2: 0
automap: 1
skipcrossduplicates: 0
custom_params: '[{"o":"folder","v":"INBOX"}]'
timeout1: 600
timeout2: 600
subscribeall: 1
dry: 0
is_running: 0
last_run: "2026-11-09 08:20:01"
success: 1
exit_status: EX_OK
created: "2026-11-03 09:40:09"
modified: "2026-11-03 09:42:21"
active: 1
source_id: 3
custom_params_legacy: null
prio: 0
source_name: Old provider
source_description: Migration from the old provider
source_host: imap.example.com
source_port: 993
source_enc: SSL
source_auth_type: PLAIN
source_created_by: API
source_scope: domain
source_oauth_flow: client_credentials
source_active: 1
source_oauth_token_expires: null
source_oauth_last_refresh_error: null
user_token_expires: null
user_token_error: null
user_token_exists: 0
log: "Transfer started at Mon Nov 9 08:20:02 2026\n..."
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/syncjobs/{mailbox}:
get:
summary: Get sync jobs of a mailbox
description: >-
The sync jobs of a local mailbox with their logs, in queue order.
Domain admins may read their mailboxes, users their own. A value that is
no email address returns the caller's own jobs.
operationId: getMailboxSyncJobs
tags:
- Sync jobs
parameters:
- name: mailbox
in: path
required: true
description: Local mailbox (`user2` of the jobs)
schema:
type: string
example: alice@example.org
responses:
"200":
description: The sync jobs of the mailbox
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SyncJob"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/syncjobs/{mailbox}/no_log:
get:
summary: Get sync jobs of a mailbox without logs
description: >-
Like `GET /api/v1/get/syncjobs/{mailbox}`, with an empty `log`.
operationId: getMailboxSyncJobsWithoutLog
tags:
- Sync jobs
parameters:
- name: mailbox
in: path
required: true
description: Local mailbox (`user2` of the jobs)
schema:
type: string
example: alice@example.org
responses:
"200":
description: The sync jobs of the mailbox
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SyncJob"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/syncjob_source/all:
get:
summary: Get sync sources
description: >-
The sync sources the caller may see, ordered by name. Domain admins see
their own, `all` sources and those for their domains or mailboxes or
created by their mailboxes; users their own, `all` sources and those
for them or their domain.
operationId: getSyncJobSources
tags:
- Sync jobs
responses:
"200":
description: The sync sources
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SyncJobSource"
example:
- id: 3
name: Old provider
description: Migration from the old provider
created_by: API
scope: domain
host1: imap.example.com
port1: 993
enc1: SSL
verify_cert: 1
auth_type: PLAIN
oauth_flow: client_credentials
oauth_token_endpoint: null
oauth_authorize_endpoint: null
oauth_userinfo_endpoint: null
oauth_client_id: null
oauth_scope: null
oauth_extra_params: null
oauth_token_expires: null
oauth_last_refresh_error: null
oauth_last_refresh_attempt: null
created: "2026-11-03 09:42:21"
modified: null
active: 1
domains:
- example.org
users: []
can_edit: true
host: imap.example.com
port: 993
enc: SSL
has_client_secret: false
has_access_token: false
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/tls-policy-map/{id}:
get:
tags:
- Outgoing TLS Policy Map Overrides
summary: Get TLS policy maps
operationId: getTlsPolicyMaps
description: >-
`all` lists the TLS policy maps, an ID returns one map with an extra
member `"0": null`. `{}` if there is none or the caller is no
administrator.
parameters:
- name: id
in: path
required: true
description: "`all` or the ID of a TLS policy map"
schema:
type: string
example: all
responses:
"200":
description: The list of TLS policy maps (`all`) or one TLS policy map
content:
application/json:
schema:
anyOf:
- type: array
items:
$ref: "#/components/schemas/TlsPolicyMap"
- $ref: "#/components/schemas/TlsPolicyMap"
examples:
all:
summary: get/tls-policy-map/all
value:
- id: 2
dest: example.com
policy: encrypt
parameters: protocols=>=TLSv1.2
active: 1
created: "2026-11-06 12:00:31"
modified: null
one:
summary: get/tls-policy-map/2
value:
id: 2
dest: example.com
policy: encrypt
parameters: protocols=>=TLSv1.2
active: 1
created: "2026-11-06 12:00:31"
modified: null
"0": null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/tls-policy-map:
post:
tags:
- Outgoing TLS Policy Map Overrides
summary: Update TLS policy maps
operationId: editTlsPolicyMap
description: >-
Changes the TLS policy maps in `items`; fields not sent keep their
value. An error stops the call; an existing destination answers
`recipient_map_entry_exists`.
Messages: `tls_policy_map_entry_saved`; errors
`tls_policy_map_dest_invalid`, `tls_policy_map_parameter_invalid`.
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: IDs of the TLS policy maps, a single value or a list
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
attr:
type: object
properties:
dest:
type: string
description: Destination, e.g. `example.org` or `[mail.example.org]:25`
policy:
type: string
enum:
- none
- may
- encrypt
- dane
- dane-only
- fingerprint
- verify
- secure
parameters:
type: string
description: Empty or space-separated `name=value` attributes
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
required:
- items
- attr
example:
items:
- 2
attr:
policy: dane
parameters: ""
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/transport/{id}:
get:
tags:
- Routing
summary: Get transport maps
operationId: getTransports
description: >-
`all` lists the transport maps, an ID returns one; the password is in
clear text. `{}` if there is none or the caller is no administrator.
parameters:
- name: id
in: path
required: true
description: "`all` or the ID of a transport map"
schema:
type: string
example: all
responses:
"200":
description: The list of transport maps (`all`) or one entry
content:
application/json:
schema:
anyOf:
- type: array
items:
$ref: "#/components/schemas/Transport"
- $ref: "#/components/schemas/Transport"
examples:
all:
summary: get/transport/all
value:
- id: 4
is_mx_based: 0
destination: example.com
nexthop: "[mx.example.com]:25"
username: ""
password: ""
active: 1
password_short: "..."
- id: 5
is_mx_based: 1
destination: .*\.google\.com
nexthop: "[smtp.example.net]:587"
username: relay-user@example.net
password: Secret-Passphrase-42
active: 1
password_short: Sec...
one:
summary: get/transport/4
value:
id: 4
is_mx_based: 0
destination: example.com
nexthop: "[mx.example.com]:25"
username: ""
password: ""
active: 1
password_short: "..."
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/relayhost:
post:
tags:
- Routing
summary: Update sender-dependent transports
operationId: editRelayhost
description: >-
Changes the sender-dependent transports in `items`; fields not sent
and an empty `hostname` keep their value.
Messages: `object_modified`; errors `relayhost_invalid`.
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: IDs of the sender-dependent transports, a single value or a list
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
attr:
type: object
properties:
hostname:
type: string
description: Next hop, e.g. `[smtp.example.com]:587`
username:
type: string
description: SMTP user name, empty for no authentication
password:
type: string
description: SMTP password
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
required:
- items
- attr
example:
items:
- 1
attr:
password: New-Secret-Passphrase-43
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/transport:
post:
tags:
- Routing
summary: Update transport maps
operationId: editTransport
description: >-
Changes the transport maps in `items`; fields not sent keep their
value. An empty `username` also clears the password; credentials apply
to all entries of the next hop. Destination and next-hop errors stop
the call.
Messages: `object_modified`; errors `relayhost_invalid`,
`transport_dest_exists`, `invalid_destination`, `next_hop_interferes`.
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: IDs of the transport maps, a single value or a list
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
attr:
type: object
properties:
destination:
type: string
description: One destination (see add/transport)
nexthop:
type: string
description: Next hop, e.g. `[mx.example.com]:25`
username:
type: string
description: SMTP user name; empty removes the credentials
password:
type: string
description: SMTP password
is_mx_based:
type: [boolean, integer, string]
description: 1 = `destination` is a regular expression for MX names
active:
type: [boolean, integer, string]
description: 1 = active, 0 = inactive
required:
- items
- attr
example:
items:
- 4
attr:
nexthop: "[mx2.example.com]:25"
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/cors:
post:
summary: Edit CORS settings
description: >-
Sets the origins and methods allowed to call the API from a browser. A
missing value is reset to its default.
Messages: `cors_headers_edited`; errors `cors_invalid_origin`,
`cors_invalid_method`.
operationId: editCors
tags:
- Cross-Origin Resource Sharing (CORS)
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
attr:
type: object
properties:
allowed_origins:
description: >-
`scheme://host[:port]` (http/https, no path) or `*`; a
list or one origin per line. Default: the mailcow URL.
oneOf:
- type: array
items:
type: string
- type: string
allowed_methods:
description: >-
Uppercase; a list or a string with single separators
(`GET,POST`, not `GET, POST`). Default: all four.
oneOf:
- type: array
items:
type: string
enum:
- GET
- POST
- PUT
- DELETE
- type: string
required:
- attr
example:
attr:
allowed_origins:
- https://app.example.org
- https://admin.example.com:8443
allowed_methods:
- GET
- POST
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/spam-score/{mailbox}:
get:
tags:
- Mailbox user settings
summary: Get the spam score of a mailbox
operationId: getSpamScore
description: >-
The spam thresholds of the mailbox, its own or the server default. `{}`
without access.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: Thresholds
content:
application/json:
schema:
$ref: "#/components/schemas/SpamScore"
example:
score: "6,12"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/spam-score:
post:
tags:
- Mailbox user settings
summary: Set the spam score of mailboxes
operationId: editSpamScore
description: >-
Sets the spam thresholds of the mailboxes: from the first value mail
goes to junk, from the second it is rejected. `default` removes the own
values. Needs the user ACL `spam_score`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
$ref: "#/components/schemas/MailboxItems"
attr:
type: object
required:
- spam_score
properties:
spam_score:
type: string
description: '"low,high" (numbers) or "default"'
examples:
- "6,12"
- default
example:
items:
- john.doe@example.org
attr:
spam_score: "6,12"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/mailbox/template:
post:
tags:
- Mailboxes
summary: Create a mailbox template
operationId: addMailboxTemplate
description: >-
Saves a named set of mailbox settings that `add/mailbox` uses as
defaults. Without `acl` it grants no user ACL.
Messages: `template_added`; errors `template_exists`,
`quarantine_category_invalid`.
requestBody:
required: true
content:
application/json:
schema:
allOf:
- type: object
required:
- template
properties:
template:
type: string
description: Name of the template
- $ref: "#/components/schemas/MailboxTemplateInput"
example:
template: Sales
quota: 2048
tags:
- sales
quarantine_notification: daily
quarantine_category: reject
rl_value: 100
rl_frame: h
active: 1
protocol_access:
- imap
- smtp
- sieve
acl:
- spam_alias
- spam_score
- app_passwds
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/mailbox/all:
get:
tags:
- Mailboxes
summary: Get all mailboxes
operationId: getMailboxes
description: >-
All mailboxes of the domains the caller manages, without resources.
`{}` if none.
parameters:
- $ref: "#/components/parameters/MailboxTagsQuery"
responses:
"200":
description: List of mailboxes
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Mailbox"
examples:
mailboxes:
$ref: "#/components/examples/MailboxList"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox/all/{domains}:
get:
tags:
- Mailboxes
summary: Get the mailboxes of domains
operationId: getMailboxesOfDomains
description: >-
Like `get/mailbox/all` for the given domains. Caution: an unknown or
foreign domain adds all mailboxes the caller manages.
parameters:
- name: domains
in: path
required: true
description: Domain name or comma-separated list of domain names
schema:
type: string
example: example.org
- $ref: "#/components/parameters/MailboxTagsQuery"
responses:
"200":
description: List of mailboxes
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Mailbox"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox/reduced:
get:
tags:
- Mailboxes
summary: Get all mailboxes (reduced details)
operationId: getMailboxesReduced
description: >-
Like `get/mailbox/all` without the costly fields named in `Mailbox`;
faster on large installations.
parameters:
- $ref: "#/components/parameters/MailboxTagsQuery"
responses:
"200":
description: List of mailboxes
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Mailbox"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox/reduced/{domains}:
get:
tags:
- Mailboxes
summary: Get the mailboxes of domains (reduced details)
operationId: getMailboxesReducedOfDomains
description: >-
Like `get/mailbox/reduced` for the given domains; an unknown domain
adds all mailboxes the caller manages.
parameters:
- name: domains
in: path
required: true
description: Domain name or comma-separated list of domain names
schema:
type: string
example: example.org,example.com
- $ref: "#/components/parameters/MailboxTagsQuery"
responses:
"200":
description: List of mailboxes
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Mailbox"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox/template/all:
get:
tags:
- Mailboxes
summary: Get all mailbox templates
operationId: getMailboxTemplates
description: >-
All mailbox templates, also for domain admins. `{}` if none.
responses:
"200":
description: List of templates
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/MailboxTemplate"
example:
- id: 2
template: Default
type: mailbox
attributes:
tags: []
quota: 0
quarantine_notification: hourly
quarantine_category: reject
rl_frame: s
rl_value: ""
force_pw_update: 0
force_tfa: 0
sogo_access: 1
active: 1
tls_enforce_in: 0
tls_enforce_out: 0
imap_access: 1
pop3_access: 1
smtp_access: 1
sieve_access: 1
eas_access: 1
dav_access: 1
acl_spam_alias: 1
acl_tls_policy: 1
acl_spam_score: 1
acl_spam_policy: 1
acl_delimiter_action: 1
acl_syncjobs: 0
acl_eas_reset: 1
acl_sogo_profile_reset: 0
acl_pushover: 1
acl_quarantine: 1
acl_quarantine_attachments: 1
acl_quarantine_notification: 1
acl_quarantine_category: 1
acl_app_passwds: 1
created: "2026-09-21 10:23:08"
modified: null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/mailbox/template/{id}:
get:
tags:
- Mailboxes
summary: Get a mailbox template
operationId: getMailboxTemplate
description: >-
One mailbox template by ID, also for domain admins. `{}` if not found.
parameters:
- name: id
in: path
required: true
description: Template ID
schema:
type: integer
example: 2
responses:
"200":
description: The template
content:
application/json:
schema:
$ref: "#/components/schemas/MailboxTemplate"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/mailbox/template:
post:
tags:
- Mailboxes
summary: Update mailbox templates
operationId: editMailboxTemplate
description: >-
Changes mailbox templates and passes the change on to mailboxes that
use them as group template. `Default` keeps its name. Send the complete
template: fields not sent are reset (`quota` to 0, protocol and ACL
settings lost), and `quarantine_category` is required.
Messages: `template_modified`; errors `template_id_invalid`,
`quarantine_category_invalid`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Template ID or list of template IDs
oneOf:
- type: integer
- type: array
items:
type: integer
attr:
allOf:
- type: object
properties:
template:
type: string
description: New name of the template (not for "Default")
- $ref: "#/components/schemas/MailboxTemplateInput"
example:
items:
- 3
attr:
template: Sales
quota: 4096
tags:
- sales
tagged_mail_handler: subfolder
quarantine_notification: daily
quarantine_category: reject
rl_value: 100
rl_frame: h
force_pw_update: 0
force_tfa: 0
sogo_access: 1
active: 1
tls_enforce_in: 0
tls_enforce_out: 1
protocol_access:
- imap
- smtp
- sieve
- dav
acl:
- spam_alias
- spam_score
- delimiter_action
- app_passwds
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/rename-mbox:
post:
tags:
- Mailboxes
summary: Rename a mailbox
operationId: renameMailbox
description: >-
Renames `old_local_part@domain` to `new_local_part@domain`, including
maildir, aliases and SOGo account. The mailbox is named in `attr`, not
`items`, and must be active (1 or 2). Also for domain admins. Answers
`mailbox_renamed`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- attr
properties:
items:
description: Not used
attr:
type: object
required:
- domain
- old_local_part
- new_local_part
properties:
domain:
type: string
description: Domain of the mailbox
old_local_part:
type: string
description: Current local part
new_local_part:
type: string
description: New local part
create_alias:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
description: 1 creates an alias from the old to the new address
example:
items: []
attr:
domain: example.org
old_local_part: john.doe
new_local_part: john
create_alias: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/mailbox/template:
post:
tags:
- Mailboxes
summary: Delete mailbox templates
operationId: deleteMailboxTemplate
description: >-
Deletes mailbox templates by ID; `Default` is kept silently. Answers
`template_removed`.
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Template IDs
items:
type: integer
example:
- 3
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/last-login/{mailbox}:
get:
tags:
- Mailboxes
summary: Get the last logins of a mailbox
operationId: getLastLogin
description: >-
Logins of the mailbox in the last 7 days (`sasl`, the latest per
address, service and app password) and its previous UI login (`ui`,
only for admins and the mailbox user itself).
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: Logins
content:
application/json:
schema:
$ref: "#/components/schemas/LastLogin"
example:
ui:
remote: 198.51.100.23
time: 1793011200
sasl:
- real_rip: 198.51.100.23
datetime: "2026-11-09 08:12:44"
service: imap
app_password: 23
app_password_name: Thunderbird
location: DE
- real_rip: Web/EAS/Internal (172.22.1.248)
datetime: "2026-11-08 17:03:10"
service: SOGO
app_password: 0
app_password_name: null
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/last-login/{mailbox}/{days}:
get:
tags:
- Mailboxes
summary: Get the last logins of a mailbox for a period
operationId: getLastLoginDays
description: >-
Like `get/last-login/{mailbox}` for the last `{days}` days; values
below 1 mean 7.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
- name: days
in: path
required: true
description: Number of days
schema:
type: integer
minimum: 1
example: 30
responses:
"200":
description: Logins
content:
application/json:
schema:
$ref: "#/components/schemas/LastLogin"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/reset-last-login/{mailbox}:
get:
tags:
- Mailboxes
summary: Clear the login history of a mailbox
operationId: resetLastLogin
description: >-
Deletes the login history of the mailbox. A `get` route that changes
data: read-only API keys can call it. Always answers `true`.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: Done
content:
application/json:
schema:
type: boolean
example: true
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/delete/eas_cache:
post:
tags:
- Mailboxes
summary: Reset the ActiveSync devices of mailboxes
operationId: deleteEasCache
description: >-
Deletes the ActiveSync device cache of the mailboxes, so devices sync
from scratch. Needs the user ACL `eas_reset`; a mailbox user may reset
only its own.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MailboxItems"
example:
- john.doe@example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/sogo_profile:
post:
tags:
- Mailboxes
summary: Reset the SOGo profile of mailboxes
operationId: deleteSogoProfile
description: >-
Deletes the SOGo data of the mailboxes: profile, settings, calendars
and address books. Needs the user ACL `sogo_profile_reset`; a mailbox
user may reset only its own.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MailboxItems"
example:
- john.doe@example.org
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/bcc-destination-options:
get:
tags:
- Mailboxes
summary: Get the possible BCC map destinations
operationId: getBccDestinationOptions
description: >-
What a BCC map can be bound to: the caller's domains, their mailboxes
with their aliases, and alias domains. Empty keys are left out.
responses:
"200":
description: Domains, mailboxes with their addresses, alias domains
content:
application/json:
schema:
type: object
properties:
domains:
type: array
items:
type: string
mailboxes:
type: object
description: Mailbox address → the mailbox and its aliases
additionalProperties:
type: array
items:
type: string
alias_domains:
type: array
items:
type: string
example:
domains:
- example.org
mailboxes:
john.doe@example.org:
- john.doe@example.org
- sales@example.org
jane.roe@example.org:
- jane.roe@example.org
alias_domains:
- example.net
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/search/mailbox:
post:
tags:
- Mailboxes
summary: Search mailboxes page by page
operationId: searchMailboxes
description: >-
Server-side search behind the UI mailbox table (DataTables format) over
the mailboxes the caller manages. Read-only API keys may use it;
mailbox users get `403`.
Columns: 2 address, 3 quota, 4 last mail login, 5 last password change,
6 quota in use, 7 name, 20 messages, 23 tags, 24 active. Send 4, 5, 6
and 20 as not searchable and 23 as not orderable, else the query fails.
`recordsTotal` equals `recordsFiltered`.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/MailboxSearchRequest"
example:
draw: 1
start: 0
length: 25
search:
value: john
order:
- column: 2
dir: asc
columns:
- searchable: false
orderable: false
- searchable: false
orderable: false
- data: username
searchable: true
orderable: true
- searchable: false
orderable: true
- searchable: false
orderable: true
- searchable: false
orderable: true
- searchable: false
orderable: true
- data: name
searchable: true
orderable: true
responses:
"200":
description: >-
One page of mailboxes. A failing database query answers
`{"error": "An SQL error occurred: ..."}` instead.
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/MailboxSearchResult"
- type: object
properties:
error:
type: string
examples:
page:
$ref: "#/components/examples/MailboxSearchPage"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
description: The caller is a mailbox user or not logged in
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
type: error
msg: Insufficient permissions
/api/v1/edit/identity-provider:
post:
summary: Configure the Identity Provider
description: >-
Saves the Identity Provider configuration (Keycloak, generic OpenID
Connect or LDAP). Send the complete configuration including the secrets:
settings not sent are reset to their defaults. Changing the LDAP
`id_attribute` drops the stored links; mailboxes are matched by email
again.
Messages: `object_modified`; errors `required_data_missing`,
`invalid_authsource`, `authsource_in_use`.
operationId: editIdentityProvider
tags:
- Identity Provider
requestBody:
content:
application/json:
schema:
type: object
required:
- attr
properties:
items:
description: Not used
attr:
$ref: "#/components/schemas/IdentityProviderAttributes"
examples:
keycloak:
value:
attr:
authsource: keycloak
server_url: https://auth.example.org
realm: mailcow
client_id: mailcow
client_secret: client-secret-value
redirect_url: https://mail.example.org
redirect_url_extra:
- https://webmail.example.org
version: 26.1.3
login_provisioning: 1
mailpassword_flow: 0
periodic_sync: 1
import_users: 1
sync_interval: 15
offboarding: 1
offboarding_limit: 10
group_sync: 1
group_autocreate: 1
group_paths: /mailcow/*
group_default_domain: example.org
default_template: Default
mappers:
- staff
templates:
- Staff
ldap:
value:
attr:
authsource: ldap
host: ldap1.example.org,ldap2.example.org
port: 636
use_ssl: 1
use_tls: 0
ignore_ssl_error: 0
basedn: dc=example,dc=org
binddn: cn=mailcow,ou=services,dc=example,dc=org
bindpass: bind-password
username_field: mail
filter: (objectClass=inetOrgPerson)
attribute_field: departmentNumber
login_provisioning: 1
periodic_sync: 1
import_users: 1
sync_interval: 30
group_sync: 1
group_filter: (objectClass=groupOfNames)
group_member_mode: member
group_member_attribute: member
default_template: Default
generic-oidc:
value:
attr:
authsource: generic-oidc
authorize_url: https://sso.example.org/application/o/authorize/
token_url: https://sso.example.org/application/o/token/
userinfo_url: https://sso.example.org/application/o/userinfo/
client_id: mailcow
client_secret: client-secret-value
redirect_url: https://mail.example.org
client_scopes: openid profile email mailcow_template
login_provisioning: 1
default_template: Default
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/identity-provider:
get:
summary: Get Identity Provider settings
description: >-
The stored Identity Provider settings, also those of providers
configured before. Read/write API keys get the secrets in plain text,
read-only keys `*`. Without a configuration it answers
`{"login_provisioning": 1}`.
operationId: getIdentityProvider
tags:
- Identity Provider
responses:
"200":
description: The settings
content:
application/json:
schema:
$ref: "#/components/schemas/IdentityProviderSettings"
example:
authsource: keycloak
server_url: https://auth.example.org
realm: mailcow
client_id: mailcow
client_secret: "*"
redirect_url: https://mail.example.org
redirect_url_extra:
- https://webmail.example.org
version: 26.1.3
mailpassword_flow: "0"
periodic_sync: "1"
import_users: "1"
sync_interval: "15"
ignore_ssl_error: false
login_provisioning: true
group_paths: /mailcow/*
offboarding: "1"
offboarding_limit: "10"
group_sync: "1"
group_autocreate: "1"
group_default_domain: example.org
default_template: Default
mappers:
- staff
templates:
- Staff
access_token: "*"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/identity-provider-test:
post:
summary: Test an Identity Provider connection
description: >-
Tests the connection data in `attr` without storing it; stored settings
are not used, so send the secrets too. Keycloak must issue a
client_credentials token and generic-oidc answer OPTIONS on `token_url`
(HTTP 200 within 7 s); LDAP must bind. The answer has no details, and a
missing or unknown `authsource` answers success without a test.
operationId: testIdentityProvider
tags:
- Identity Provider
requestBody:
content:
application/json:
schema:
type: object
required:
- attr
properties:
items:
description: Not used
attr:
type: object
required:
- authsource
properties:
authsource:
type: string
enum:
- keycloak
- generic-oidc
- ldap
server_url:
type: string
description: Keycloak base URL
realm:
type: string
description: Keycloak realm
client_id:
type: string
description: Keycloak client id
client_secret:
type: string
description: Keycloak client secret
token_url:
type: string
description: generic-oidc token endpoint
ignore_ssl_error:
type:
- boolean
- integer
- string
description: Do not verify the TLS certificate
host:
type: string
description: LDAP host, or several separated by commas
port:
type:
- integer
- string
description: LDAP port
basedn:
type: string
binddn:
type: string
bindpass:
type: string
use_ssl:
type:
- boolean
- integer
- string
description: LDAPS
use_tls:
type:
- boolean
- integer
- string
description: StartTLS, ignored with `use_ssl`
example:
attr:
authsource: keycloak
server_url: https://auth.example.org
realm: mailcow
client_id: mailcow
client_secret: client-secret-value
ignore_ssl_error: 0
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/identity-provider:
post:
summary: Delete the Identity Provider configuration
description: >-
Deletes all Identity Provider settings, mailbox links and the sync
history. Refused while any mailbox uses an external provider. The body
must be valid JSON, e.g. `[]`.
Messages: `item_deleted`; errors `authsource_in_use`.
operationId: deleteIdentityProvider
tags:
- Identity Provider
requestBody:
content:
application/json:
schema:
description: Not used, any JSON value
example: []
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/filter:
post:
tags:
- Mailbox filters
summary: Create a Sieve filter
operationId: addFilter
description: >-
Adds a Sieve script to a mailbox. Needs the ACL `filters` (admins,
domain admins). Activating a filter deactivates the other filters of
the same type and mailbox.
Messages: `mailbox_modified`; errors `sieve_error`, `no_user_defined`,
`script_empty`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- username
- script_data
- script_desc
- filter_type
properties:
username:
type: string
description: Mailbox of the filter
script_desc:
type: string
description: Description
script_data:
type: string
description: The Sieve script
filter_type:
type: string
enum:
- prefilter
- postfilter
description: Runs before (prefilter) or after (postfilter) the user's own filters
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
default: 0
example:
username: john.doe@example.org
script_desc: Move newsletters
script_data: |-
require "fileinto";
if header :contains "List-Id" "newsletter" {
fileinto "Newsletters";
}
filter_type: prefilter
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/filters/all:
get:
tags:
- Mailbox filters
summary: Get all Sieve filters
operationId: getFilters
description: >-
The Sieve filters of all mailboxes the caller manages, `{}` if none.
responses:
"200":
description: List of filters
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SieveFilter"
example:
- active: 1
id: 7
username: john.doe@example.org
filter_type: prefilter
script_data: |-
require "fileinto";
if header :contains "List-Id" "newsletter" {
fileinto "Newsletters";
}
script_desc: Move newsletters
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/filters/{mailbox}:
get:
tags:
- Mailbox filters
summary: Get the Sieve filters of a mailbox
operationId: getMailboxFilters
description: >-
The Sieve filters of the mailbox, `{}` if none or no access.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: List of filters
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SieveFilter"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/filter:
post:
tags:
- Mailbox filters
summary: Update Sieve filters
operationId: editFilter
description: >-
Changes filters by ID; fields not sent keep their value. Needs the ACL
`filters` (admins, domain admins). Activating a filter deactivates the
others of the same type and mailbox. An unknown ID answers
`access_denied`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- items
- attr
properties:
items:
description: Filter ID or list of IDs
oneOf:
- type: integer
- type: array
items:
type: integer
attr:
type: object
properties:
script_desc:
type: string
script_data:
type: string
filter_type:
type: string
enum:
- prefilter
- postfilter
active:
type: [integer, string]
enum: [0, 1, "0", "1"]
example:
items:
- 7
attr:
active: 0
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/filter:
post:
tags:
- Mailbox filters
summary: Delete Sieve filters
operationId: deleteFilter
description: >-
Deletes filters by ID; IDs that are not numeric are skipped. Needs the
ACL `filters` (admins, domain admins).
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Filter IDs
items:
type: integer
example:
- 7
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/active-user-sieve/{mailbox}:
get:
tags:
- Mailbox filters
summary: Get the active Sieve script of a mailbox
operationId: getActiveUserSieve
description: >-
The Sieve script the user activated in a mail client or SOGo, as a list
with one string. `{}` if none or no access.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: The script as the only element of a list
content:
application/json:
schema:
type: array
maxItems: 1
items:
type: string
example:
- |-
require ["fileinto"];
if header :contains "subject" "invoice" {
fileinto "Invoices";
}
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/add/mailbox-policy:
post:
tags:
- Mailbox antispam policies
summary: Add a sender to the allow or deny list of a mailbox
operationId: addMailboxPolicy
description: >-
Adds a sender to the allow list (`wl`, never spam) or deny list (`bl`,
rejected) of a mailbox. Needs the user ACL `spam_policy`.
Messages: `mailbox_modified`; errors `policy_list_from_invalid`,
`policy_list_from_exists`.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- username
- object_list
- object_from
properties:
username:
type: string
description: Mailbox
object_list:
type: string
enum:
- wl
- bl
description: wl = allow list, bl = deny list
object_from:
type: string
description: "Sender address, domain or pattern; allowed: letters, digits, `@ _ . - *`"
example:
username: john.doe@example.org
object_list: bl
object_from: "*@spam.example.com"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/policy_wl_mailbox/{mailbox}:
get:
tags:
- Mailbox antispam policies
summary: Get the allow list of a mailbox
operationId: getMailboxPolicyAllowList
description: >-
The allow list entries of the mailbox and of its domain (see `object`).
`{}` if none or no access.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: List of entries
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SpamPolicyEntry"
example:
- object: john.doe@example.org
value: "*@partner.example.com"
prefid: 12
- object: example.org
value: newsletter@example.net
prefid: 4
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/policy_bl_mailbox/{mailbox}:
get:
tags:
- Mailbox antispam policies
summary: Get the deny list of a mailbox
operationId: getMailboxPolicyDenyList
description: >-
Like `get/policy_wl_mailbox/{mailbox}` for the deny list.
parameters:
- name: mailbox
in: path
required: true
description: Mailbox address
schema:
type: string
example: john.doe@example.org
responses:
"200":
description: List of entries
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/SpamPolicyEntry"
example:
- object: john.doe@example.org
value: "*@spam.example.com"
prefid: 13
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/delete/mailbox-policy:
post:
tags:
- Mailbox antispam policies
summary: Delete allow or deny list entries of mailboxes
operationId: deleteMailboxPolicy
description: >-
Deletes allow or deny list entries of mailboxes by `prefid`. Needs the
user ACL `spam_policy`. Domain entries are refused; use
`delete/domain-policy`.
requestBody:
required: true
content:
application/json:
schema:
type: array
description: prefid values
items:
type: integer
example:
- 13
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/add/rsetting:
post:
summary: Add Rspamd settings rule
description: >-
Adds a rule to the Rspamd settings map. `content` is an Rspamd settings
entry; `GET /api/v1/get/presets/rspamd` has examples. Without `desc`
nothing is saved and the answer is empty.
Messages: `settings_map_added`; errors `map_content_empty`.
operationId: addRspamdSetting
tags:
- Rspamd
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/RspamdSettingAttributes"
example:
desc: Disable all but DKIM and rate limit for authenticated users
content: |-
priority = 10;
authenticated = yes;
apply "default" {
symbols_enabled = ["DKIM_SIGNED", "RATELIMITED", "RATELIMIT_UPDATE", "RATELIMIT_CHECK"];
}
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/rsetting/{id}:
get:
summary: Get Rspamd settings rules
description: >-
Returns one rule of the Rspamd settings map, or a list of all rules
with `all`.
operationId: getRspamdSettings
tags:
- Rspamd
parameters:
- name: id
in: path
required: true
description: "`all` or the ID of a rule"
schema:
type: string
example: all
responses:
"200":
description: The rule, or the list of rules for `all`
content:
application/json:
schema:
oneOf:
- type: array
items:
$ref: "#/components/schemas/RspamdSetting"
- $ref: "#/components/schemas/RspamdSetting"
example:
- id: 1
desc: Disable Rspamd for example.org
content: |-
priority = 10;
rcpt = "/.*@example\.org$/";
from = "/.*/";
apply "default" {
MAILCOW_WHITE = -9999.0;
}
symbols [
"MAILCOW_WHITE"
]
active: 1
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/rsetting:
post:
summary: Edit Rspamd settings rules
description: >-
Changes rules of the Rspamd settings map. Fields not sent, and an empty
`desc` or `content`, keep the old value.
Messages: `object_modified`; errors `settings_map_invalid`.
operationId: editRspamdSetting
tags:
- Rspamd
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: ID or list of IDs of the rules
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
attr:
type: object
properties:
desc:
type: string
description: Short description (empty = keep)
content:
type: string
description: Rule content (empty = keep)
active:
type: [boolean, integer, string]
description: 1 = the rule is handed to Rspamd, 0 = inactive (not sent = keep)
required:
- items
- attr
example:
items:
- 1
attr:
desc: Disable Rspamd for example.org
active: "0"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/rsetting:
post:
summary: Delete Rspamd settings rules
description: >-
Deletes rules of the Rspamd settings map. Answers
`settings_map_removed` for every ID, even unknown ones.
operationId: deleteRspamdSettings
tags:
- Rspamd
requestBody:
content:
application/json:
schema:
description: IDs of the rules (a single ID works too)
oneOf:
- type: array
items:
type: [integer, string]
- type: [integer, string]
example:
- 1
- 2
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/rspamd-map:
post:
summary: Edit Rspamd global regex maps
description: >-
Replaces the content of global Rspamd regex maps (Global filters in the
UI). One regular expression per line, `#` starts a comment; unlike the
UI, the API does not check the expressions. Each map takes about a
second.
Messages: `object_modified`; errors `global_map_invalid`,
`global_map_write_error`.
operationId: editRspamdMap
tags:
- Rspamd
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: File name or list of file names of the maps; all of them get the same content
oneOf:
- type: array
items:
$ref: "#/components/schemas/RspamdRegexMap"
- $ref: "#/components/schemas/RspamdRegexMap"
attr:
type: object
properties:
rspamd_map_data:
type: string
description: New content of the map (trimmed, replaces the whole file)
required:
- rspamd_map_data
required:
- items
- attr
example:
items:
- global_smtp_from_blacklist.map
attr:
rspamd_map_data: |-
# Envelope senders to reject
/^spammer@example\.com$/i
/@spam\.example\.net$/i
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/rspamd/actions:
get:
summary: Get Rspamd action statistics
description: >-
Returns how many messages Rspamd handled with each action, as
`[action, count]` pairs. Greylisted messages count as `soft reject`.
`{}` when Rspamd does not answer.
operationId: getRspamdActions
tags:
- Rspamd
responses:
"200":
description: List of `[action, count]` pairs
content:
application/json:
schema:
type: array
items:
type: array
prefixItems:
- type: string
description: Rspamd action
- type: integer
description: Number of messages
minItems: 2
maxItems: 2
example:
- - reject
- 38
- - soft reject
- 1
- - rewrite subject
- 0
- - add header
- 6
- - no action
- 255
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/presets/{kind}:
get:
summary: Get Rspamd or Sieve presets
description: >-
Returns the example presets of the UI: `rspamd` for Rspamd settings
rules, `sieve` for Sieve filters. `headline` is in the session
language. Admins and domain admins.
operationId: getPresets
tags:
- Rspamd
- Global filters
parameters:
- name: kind
in: path
required: true
description: Kind of presets
schema:
type: string
enum:
- rspamd
- sieve
example: rspamd
responses:
"200":
description: List of presets
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Preset"
example:
- name: preset_1
headline: Disable all but DKIM and rate limit for authenticated users
content: |-
priority = 10;
authenticated = yes;
apply "default" {
symbols_enabled = ["BCC", "DKIM_SIGNED", "RATELIMITED", "RATELIMIT_UPDATE", "RATELIMIT_CHECK", "DYN_RL_CHECK", "HISTORY_SAVE", "MILTER_HEADERS", "ARC_SIGNED"];
}
- name: preset_4
headline: Disable Rspamd for a domain
content: |-
priority = 10;
rcpt = "/.*@example.org$/";
from = "/.*/";
apply "default" {
MAILCOW_WHITE = -9999.0;
}
symbols [
"MAILCOW_WHITE"
]
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/add/global-filter:
post:
summary: Save a global Sieve filter
description: >-
Replaces the global Sieve prefilter or postfilter and restarts Dovecot.
A script with errors is not saved.
Messages: `global_filter_written`, `dovecot_restart_success`; errors
`sieve_error`, `invalid_filter_type`, `global_filter_write_error`,
`dovecot_restart_failed`.
operationId: addGlobalFilter
tags:
- Global filters
requestBody:
content:
application/json:
schema:
type: object
properties:
filter_type:
type: string
enum:
- prefilter
- postfilter
description: Which global filter to replace
script_data:
type: string
description: The Sieve script (CRLF and CR line ends become LF)
required:
- filter_type
- script_data
example:
filter_type: postfilter
script_data: |-
require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
}
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/global_filters/all:
get:
summary: Get the global Sieve filters
description: >-
Returns the global Sieve prefilter and postfilter.
operationId: getGlobalFilters
tags:
- Global filters
responses:
"200":
description: Both scripts
content:
application/json:
schema:
$ref: "#/components/schemas/GlobalFilters"
example:
prefilter: |
# global_sieve_before script
# global_sieve_before -> user sieve_before (mailcow UI) -> user sieve_after (mailcow UI) -> global_sieve_after
postfilter: |-
# global_sieve_after script
require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
}
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/global_filters/{filter_type}:
get:
summary: Get one global Sieve filter
description: >-
Returns the global Sieve prefilter or postfilter as a JSON string;
`{}` when the script is empty.
operationId: getGlobalFilter
tags:
- Global filters
parameters:
- name: filter_type
in: path
required: true
description: Which global filter
schema:
type: string
enum:
- prefilter
- postfilter
example: prefilter
responses:
"200":
description: The Sieve script
content:
application/json:
schema:
type: string
example: |
# global_sieve_before script
# global_sieve_before -> user sieve_before (mailcow UI) -> user sieve_after (mailcow UI) -> global_sieve_after
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/quota_notification:
post:
summary: Edit quota notification settings
description: >-
Saves sender, subject and template of the mails users get when their
mailbox crosses 80 % and 95 % of its quota. Fields not sent become
empty. The current values cannot be read through the API.
Messages: `saved_settings`; errors `redis_error`.
operationId: editQuotaNotification
tags:
- Quota notifications
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: Ignored
attr:
type: object
properties:
sender:
type: string
description: Sender address (invalid address = empty)
subject:
type: string
description: Subject
html_tmpl:
type: string
description: HTML template (empty = the default template)
required:
- attr
example:
items:
- quota_notification
attr:
sender: quota-warning@example.org
subject: Quota warning
html_tmpl: ""
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/quota_notification_bcc:
post:
summary: Edit quota notification BCC of a domain
description: >-
Sets the addresses that get a copy of every quota warning of a domain;
the list replaces the old one and cannot be read through the API.
Admins and domain admins of the domain. Invalid addresses are left out,
the others are saved.
Messages: `saved_settings`; errors `goto_invalid`, `redis_error`.
operationId: editQuotaNotificationBcc
tags:
- Quota notifications
requestBody:
content:
application/json:
schema:
type: object
properties:
items:
description: Ignored
attr:
type: object
properties:
domain:
type: string
description: Domain or alias domain
bcc_rcpt:
type: string
description: Addresses, separated by space, comma, semicolon or newline
active:
type: [boolean, integer, string]
description: 1 = send the copies; becomes 0 when no valid address is left
required:
- domain
required:
- attr
example:
items:
- quota_bcc
attr:
domain: example.org
bcc_rcpt: |-
postmaster@example.org
helpdesk@example.org
active: "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/admin/all:
get:
summary: Get administrators
description: Lists all administrators, without domain administrators and the API key account.
operationId: getAdmins
tags:
- Administrators
responses:
"200":
description: The administrators, `{}` if there are none
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Admin"
example:
- username: admin
tfa_active: 1
tfa_active_int: 1
active: 1
active_int: 1
created: "2026-09-21 10:23:08"
attributes:
force_tfa: "0"
force_pw_update: "0"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/admin/{username}:
get:
summary: Get administrator
description: Details of one administrator.
operationId: getAdmin
tags:
- Administrators
parameters:
- name: username
in: path
required: true
description: Username of the administrator
schema:
type: string
example: admin
responses:
"200":
description: The administrator, `{}` if there is no administrator of this name
content:
application/json:
schema:
$ref: "#/components/schemas/Admin"
example:
username: admin
tfa_active: 0
tfa_active_int: 0
active: 1
active_int: 1
created: "2026-09-21 10:23:08"
attributes:
force_tfa: "0"
force_pw_update: "0"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/add/admin:
post:
summary: Create administrator
description: >-
Creates an administrator. The username is stored in lowercase and must
not be in use by an administrator or domain administrator. Without
`active: 1` the account is disabled.
Messages: `admin_added`; errors `object_exists`, `password_complexity`,
`password_mismatch`.
operationId: addAdmin
tags:
- Administrators
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
username:
type: string
description: Username (letters, digits, `_`, `.`, `-`; stored in lowercase)
password:
type: string
description: Password, must match the password policy
password2:
type: string
description: The password again
active:
type: [integer, string, boolean]
description: 1 = the account can log in, 0 = disabled
default: 0
required:
- username
- password
- password2
example:
username: admin2
password: "Rand0m-Passw0rd!"
password2: "Rand0m-Passw0rd!"
active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/admin:
post:
summary: Edit administrators
description: >-
Changes administrators. Fields not sent keep their value, but
`force_tfa` and `force_pw_update` are reset to 0; an empty `password`
keeps the password. FIDO2 keys are not moved on rename. The last active
administrator cannot be deactivated.
Messages: `admin_modified`; errors `username_invalid`,
`password_mismatch`, `password_complexity`; warning `no_active_admin`.
operationId: editAdmin
tags:
- Administrators
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
items:
description: Username of the administrator, or a list of usernames
oneOf:
- type: string
- type: array
items:
type: string
attr:
type: object
properties:
active:
type: [integer, string, boolean]
description: 1 = active, 0 = disabled
username_new:
type: string
description: New username (letters, digits, `_`, `.`, `-`)
password:
type: string
description: New password; empty or missing keeps the password
password2:
type: string
description: The new password again
force_tfa:
type: [integer, string, boolean]
description: 1 = the administrator must set up two-factor authentication at the next login
default: 0
force_pw_update:
type: [integer, string, boolean]
description: 1 = the administrator must change the password at the next login
default: 0
disable_tfa:
type: [integer, string, boolean]
description: Present (any value) = turn off two-factor authentication
required:
- items
- attr
example:
items:
- admin2
attr:
active: 1
password: "N3w-Passw0rd!"
password2: "N3w-Passw0rd!"
force_pw_update: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/delete/admin:
post:
summary: Delete administrators
description: >-
Deletes administrators with their two-factor authentication and FIDO2
keys.
Messages: `admin_removed`; error `username_invalid`.
operationId: deleteAdmin
tags:
- Administrators
requestBody:
required: true
content:
application/json:
schema:
type: array
description: Usernames of the administrators
items:
type: string
example:
- admin2
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/get/passwordpolicy:
get:
summary: Get password policy
description: The password policy for mailboxes, administrators and domain administrators.
operationId: getPasswordPolicy
tags:
- Password policy
responses:
"200":
description: The policy
content:
application/json:
schema:
$ref: "#/components/schemas/PasswordPolicy"
example:
length: "8"
chars: "1"
special_chars: "0"
lowerupper: "1"
numbers: "1"
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/get/passwordpolicy/html:
get:
summary: Get password policy as HTML
description: >-
The password policy as HTML snippet in the default language, as shown
below password fields.
operationId: getPasswordPolicyHtml
tags:
- Password policy
responses:
"200":
description: The HTML snippet as a JSON string
content:
application/json:
schema:
type: string
example: <p class="help-block small">- Minimum password length is 8<br>- Must contain at least one alphabetic character<br>- Must contain lowercase and uppercase characters<br>- Must contain at least one number</p>
"401":
$ref: "#/components/responses/Unauthorized"
/api/v1/edit/passwordpolicy:
post:
summary: Edit password policy
description: >-
Changes the password policy; fields not sent keep their value. Existing
passwords are not checked again.
Messages: `password_policy_saved`.
operationId: editPasswordPolicy
tags:
- Password policy
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
attr:
type: object
properties:
length:
type: [integer, string]
description: Minimum length; values below 3 keep the current length
chars:
type: [integer, string, boolean]
description: 1 = at least one letter
lowerupper:
type: [integer, string, boolean]
description: 1 = lowercase and uppercase letters
special_chars:
type: [integer, string, boolean]
description: 1 = at least one character that is no letter or digit
numbers:
type: [integer, string, boolean]
description: 1 = at least one digit
required:
- attr
example:
attr:
length: 12
chars: 1
lowerupper: 1
special_chars: 0
numbers: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/reset-password-notification:
post:
summary: Edit password reset e-mail
description: >-
Sets the password reset e-mail sent to the recovery address of a
mailbox. Fields not sent are saved as empty. With both templates empty
the defaults are used; without sender and subject, password reset is
off.
Placeholders: `{{username}}`, `{{username2}}` (recovery address),
`{{date}}`, `{{token_lifetime}}` (minutes), `{{hostname}}`, `{{link}}`.
Messages: `saved_settings`.
operationId: editPasswordResetNotification
tags:
- Password policy
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
attr:
type: object
properties:
from:
type: string
description: Sender address; an invalid address is saved as empty
subject:
type: string
description: Subject
text_tmpl:
type: string
description: Plain text template
html_tmpl:
type: string
description: HTML template (the text template becomes its alternative part)
required:
- attr
example:
attr:
from: noreply@example.org
subject: Reset your password
text_tmpl: "Hello {{username}}, open {{link}} within {{token_lifetime}} minutes to set a new password."
html_tmpl: "<p>Hello {{username}},</p><p><a href=\"{{link}}\">Set a new password</a> within {{token_lifetime}} minutes.</p>"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/app_links:
post:
summary: Edit app links
description: >-
Replaces the custom links of the Apps menu, sent as four lists of equal
length. If the lengths differ, nothing is saved, but `app_links` is
reported anyway. Empty lists remove all custom links.
Messages: `app_links`.
operationId: editAppLinks
tags:
- UI customization
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
attr:
type: object
properties:
app:
type: array
description: Names of the links
items:
type: string
href:
type: array
description: URLs shown on the login page and to users without `user_href`
items:
type: string
user_href:
type: array
description: URLs for logged-in accounts (`%u` = username); empty = `href`
items:
type: string
hide:
type: array
description: Per link, `0` shows it on the login page, any other value (even `false`) hides it
items:
type: [string, integer, boolean]
required:
- attr
example:
attr:
app:
- Wiki
- Webmail (Roundcube)
href:
- https://wiki.example.org
- https://mail.example.org/rc/
user_href:
- https://wiki.example.org
- https://mail.example.org/rc/?_user=%u
hide:
- "0"
- "1"
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/custom_login:
post:
summary: Edit login page options
description: >-
Sets the login page options. All four are replaced: a missing option
counts as 0.
Messages: `custom_login_modified`.
operationId: editCustomLogin
tags:
- UI customization
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
attr:
type: object
properties:
hide_user_quicklink:
type: [integer, string, boolean]
description: 1 = hide the link to the user login page
default: 0
hide_domainadmin_quicklink:
type: [integer, string, boolean]
description: 1 = hide the link to the domain administrator login page
default: 0
hide_admin_quicklink:
type: [integer, string, boolean]
description: 1 = hide the link to the administrator login page
default: 0
force_sso:
type: [integer, string, boolean]
description: 1 = show only the Single Sign-On button (needs an OIDC identity provider)
default: 0
required:
- attr
example:
attr:
hide_user_quicklink: 0
hide_domainadmin_quicklink: 1
hide_admin_quicklink: 1
force_sso: 0
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/ip_check:
post:
summary: Edit IP check
description: >-
Turns the dashboard IP check on or off, which asks ipv4.mailcow.email
and ipv6.mailcow.email for the public addresses.
Messages: `ip_check_opt_in_modified`.
operationId: editIpCheck
tags:
- UI customization
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
attr:
type: object
properties:
ip_check_opt_in:
type: [integer, string, boolean]
description: 1/true = enabled; anything else or missing = disabled
default: 0
required:
- attr
example:
attr:
ip_check_opt_in: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/ui_texts:
post:
summary: Edit UI texts
description: >-
Sets the texts of the mailcow UI. All values are replaced: a missing
one is saved as empty.
Messages: `ui_texts`.
operationId: editUiTexts
tags:
- UI customization
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
attr:
type: object
properties:
title_name:
type: string
description: Title of the browser window (plain text); empty = "<hostname> - mail UI"
main_name:
type: string
description: Name shown on the start page (plain text); empty = "<hostname> - mail UI"
apps_name:
type: string
description: Name of the "Apps" menu (plain text); empty = "Apps"
help_text:
type: string
description: Help text below the login form (HTML)
ui_footer:
type: string
description: Footer of every page (HTML)
ui_announcement_text:
type: string
description: Announcement for all logged-in accounts and on the login page (HTML)
ui_announcement_type:
type: string
enum:
- info
- warning
- danger
description: Style of the announcement; other values are saved as empty
ui_announcement_active:
type: [integer, string, boolean]
description: Not empty and not 0 = show the announcement
default: 0
required:
- attr
example:
attr:
title_name: Example Mail
main_name: Example Mail
apps_name: Apps
help_text: "Questions? Write to <a href=\"mailto:support@example.org\">support@example.org</a>."
ui_footer: "<a href=\"https://example.org/imprint\">Imprint</a>"
ui_announcement_text: Maintenance on Saturday from 8 to 10 am.
ui_announcement_type: warning
ui_announcement_active: 1
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
/api/v1/edit/ui_theme:
post:
summary: Edit UI theme
description: >-
Selects the UI theme by its folder name in `data/web/css/themes/`.
Messages: `ui_theme_modified`; error `ui_theme_invalid`.
operationId: editUiTheme
tags:
- UI customization
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
attr:
type: object
properties:
ui_theme:
description: Folder name of the theme, empty = default theme; of a list only the first entry counts
oneOf:
- type: string
- type: array
items:
type: string
required:
- attr
example:
attr:
ui_theme: servercow
responses:
"200":
$ref: "#/components/responses/WriteResult"
"401":
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
tags:
- name: Domains
description: >-
Domains, alias domains, domain templates, MTA-STS policies and
domain-wide footers
- name: Domain antispam policies
description: Sender allow lists (whitelists) and deny lists (blacklists) of domains
- name: Mailboxes
description: Mailboxes, their templates, tags, ACLs and logins
- name: Aliases
description: You can manage aliases
- name: Sync jobs
description: Using Syncjobs you can sync your mails with other email servers
- name: Logs
description: Logs of the mailcow containers and the UI
- name: Queue Manager
description: Manage the postfix mail queue
- name: Quarantine
description: Check what emails went to quarantine
- name: Fail2Ban
description: Manage the Netfilter fail2ban options
- name: DKIM
description: Generate, import, copy and delete DKIM keys
- name: Domain admin
description: Domain administrators, their domains and ACLs
- name: Single Sign-On
description: Login tokens for domain administrators
- name: Address Rewriting
description: BCC maps and recipient maps
- name: Outgoing TLS Policy Map Overrides
description: TLS policies for outgoing connections to single destinations
- name: oAuth Clients
description: Clients that use mailcow as OAuth2 server
- name: API Keys
description: API keys; service keys from mailcow.conf are read-only
- name: Groups
description: Mailbox groups (distribution lists, send-as rights, templates)
- name: Routing
description: Sender-dependent transports (relay hosts) and transport maps for outgoing mail
- name: Resources
description: Bookable resources (rooms, equipment, groups) for SOGo
- name: App Passwords
description: Separate passwords of a mailbox for single clients and protocols
- name: Status
description: Containers, mail storage, host and version
- name: Ratelimits
description: Edit domain ratelimits
- name: Cross-Origin Resource Sharing (CORS)
description: Origins and methods that may call the API from a browser
- name: Identity Provider
description: >-
External Identity Provider (Keycloak, OpenID Connect, LDAP): settings,
identity sync and links of mailboxes
- name: Mailbox user settings
description: >-
Settings a mailbox user changes on its own page (with the matching user
ACL): time-limited aliases, spam score, TLS policy, tagged mail,
Pushover. API keys can change them for any mailbox and must name the
mailbox; a mailbox user only for its own.
- name: Mailbox filters
description: Sieve filters of mailboxes, managed by admins and domain admins
- name: Mailbox antispam policies
description: Sender allow and deny lists of mailboxes
- name: Forwarding Hosts
description: >-
Hosts whose incoming mail is accepted unconditionally, e.g. servers that
forward mail to mailcow
- name: Rspamd
description: Rspamd settings rules, global regex maps, presets and statistics
- name: Global filters
description: Global Sieve filters that run before and after the filters of the mailboxes, Sieve presets
- name: Quota notifications
description: Mails to users whose mailbox is nearly full
- name: Administrators
description: Administrator accounts
- name: Password policy
description: Password rules and the password reset e-mail
- name: UI customization
description: Texts, links, login page and theme of the mailcow UI