Skip to content

Commit ec74692

Browse files
committed
MAX_RECIPIENTS and quota management
1 parent 4f66ec2 commit ec74692

File tree

31 files changed

+2383
-31
lines changed

31 files changed

+2383
-31
lines changed

compose.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,28 @@ services:
1919
ports:
2020
- "8913:6379"
2121

22+
redis-quotas:
23+
image: redis:7-alpine
24+
command: >
25+
redis-server
26+
--port 6380
27+
--maxmemory-policy noeviction
28+
--appendonly yes
29+
--appendfsync everysec
30+
--save 900 1
31+
--save 300 10
32+
--save 60 10000
33+
ports:
34+
- "8916:6380"
35+
volumes:
36+
- redis-quotas-data:/data
37+
healthcheck:
38+
test: ["CMD", "redis-cli", "-p", "6380", "ping"]
39+
interval: 5s
40+
timeout: 3s
41+
retries: 5
42+
restart: unless-stopped
43+
2244
opensearch:
2345
image: opensearchproject/opensearch:2.19.2
2446
environment:
@@ -355,3 +377,7 @@ services:
355377
- "8902:8802"
356378
depends_on:
357379
- postgresql
380+
381+
volumes:
382+
redis-quotas-data:
383+
driver: local

src/backend/core/api/openapi.json

Lines changed: 199 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,26 @@
232232
"type": "integer",
233233
"description": "Default maximum number of recipients per message (to + cc + bcc) for a mailbox or maildomain if no custom limit is set.",
234234
"readOnly": true
235+
},
236+
"MAX_RECIPIENTS_FOR_DOMAIN": {
237+
"type": "string",
238+
"description": "Maximum recipients per period for a domain (format: 'number/period', e.g., '1500/d' for 1500 per day). Cannot be exceeded.",
239+
"readOnly": true
240+
},
241+
"MAX_DEFAULT_RECIPIENTS_FOR_DOMAIN": {
242+
"type": "string",
243+
"description": "Default maximum recipients per period for a domain (format: 'number/period', e.g., '1000/d' for 1000 per day) if no custom limit is set.",
244+
"readOnly": true
245+
},
246+
"MAX_RECIPIENTS_FOR_MAILBOX": {
247+
"type": "string",
248+
"description": "Maximum recipients per period for a mailbox (format: 'number/period', e.g., '500/d' for 500 per day). Cannot be exceeded.",
249+
"readOnly": true
250+
},
251+
"MAX_DEFAULT_RECIPIENTS_FOR_MAILBOX": {
252+
"type": "string",
253+
"description": "Default maximum recipients per period for a mailbox (format: 'number/period', e.g., '100/d' for 100 per day) if no custom limit is set.",
254+
"readOnly": true
235255
}
236256
},
237257
"required": [
@@ -247,7 +267,11 @@
247267
"MAX_OUTGOING_BODY_SIZE",
248268
"MAX_INCOMING_EMAIL_SIZE",
249269
"MAX_RECIPIENTS_PER_MESSAGE",
250-
"MAX_DEFAULT_RECIPIENTS_PER_MESSAGE"
270+
"MAX_DEFAULT_RECIPIENTS_PER_MESSAGE",
271+
"MAX_RECIPIENTS_FOR_DOMAIN",
272+
"MAX_DEFAULT_RECIPIENTS_FOR_DOMAIN",
273+
"MAX_RECIPIENTS_FOR_MAILBOX",
274+
"MAX_DEFAULT_RECIPIENTS_FOR_MAILBOX"
251275
]
252276
}
253277
}
@@ -2880,6 +2904,42 @@
28802904
}
28812905
}
28822906
},
2907+
"/api/v1.0/mailboxes/{id}/quota/": {
2908+
"get": {
2909+
"operationId": "mailboxes_quota_retrieve",
2910+
"description": "Get the recipient quota status for this mailbox.",
2911+
"parameters": [
2912+
{
2913+
"in": "path",
2914+
"name": "id",
2915+
"schema": {
2916+
"type": "string"
2917+
},
2918+
"required": true
2919+
}
2920+
],
2921+
"tags": [
2922+
"mailboxes"
2923+
],
2924+
"security": [
2925+
{
2926+
"cookieAuth": []
2927+
}
2928+
],
2929+
"responses": {
2930+
"200": {
2931+
"content": {
2932+
"application/json": {
2933+
"schema": {
2934+
"$ref": "#/components/schemas/RecipientQuota"
2935+
}
2936+
}
2937+
},
2938+
"description": ""
2939+
}
2940+
}
2941+
}
2942+
},
28832943
"/api/v1.0/mailboxes/{id}/search/": {
28842944
"get": {
28852945
"operationId": "mailboxes_search_list",
@@ -3584,6 +3644,51 @@
35843644
}
35853645
}
35863646
},
3647+
"/api/v1.0/maildomains/{maildomain_pk}/mailboxes/{id}/quota/": {
3648+
"get": {
3649+
"operationId": "maildomains_mailboxes_quota_retrieve",
3650+
"description": "Get the recipient quota status for this mailbox.",
3651+
"parameters": [
3652+
{
3653+
"in": "path",
3654+
"name": "id",
3655+
"schema": {
3656+
"type": "string"
3657+
},
3658+
"required": true
3659+
},
3660+
{
3661+
"in": "path",
3662+
"name": "maildomain_pk",
3663+
"schema": {
3664+
"type": "string",
3665+
"format": "uuid"
3666+
},
3667+
"required": true
3668+
}
3669+
],
3670+
"tags": [
3671+
"maildomains"
3672+
],
3673+
"security": [
3674+
{
3675+
"cookieAuth": []
3676+
}
3677+
],
3678+
"responses": {
3679+
"200": {
3680+
"content": {
3681+
"application/json": {
3682+
"schema": {
3683+
"$ref": "#/components/schemas/RecipientQuota"
3684+
}
3685+
}
3686+
},
3687+
"description": ""
3688+
}
3689+
}
3690+
}
3691+
},
35873692
"/api/v1.0/maildomains/{maildomain_pk}/mailboxes/{id}/reset-password/": {
35883693
"patch": {
35893694
"operationId": "maildomains_mailboxes_reset_password",
@@ -4029,6 +4134,44 @@
40294134
}
40304135
}
40314136
},
4137+
"/api/v1.0/maildomains/{maildomain_pk}/quota/": {
4138+
"get": {
4139+
"operationId": "maildomains_quota_retrieve",
4140+
"description": "Get the recipient quota status for this mail domain.",
4141+
"parameters": [
4142+
{
4143+
"in": "path",
4144+
"name": "maildomain_pk",
4145+
"schema": {
4146+
"type": "string",
4147+
"format": "uuid",
4148+
"description": "primary key for the record as UUID"
4149+
},
4150+
"required": true
4151+
}
4152+
],
4153+
"tags": [
4154+
"maildomains"
4155+
],
4156+
"security": [
4157+
{
4158+
"cookieAuth": []
4159+
}
4160+
],
4161+
"responses": {
4162+
"200": {
4163+
"content": {
4164+
"application/json": {
4165+
"schema": {
4166+
"$ref": "#/components/schemas/RecipientQuota"
4167+
}
4168+
}
4169+
},
4170+
"description": ""
4171+
}
4172+
}
4173+
}
4174+
},
40324175
"/api/v1.0/messages/": {
40334176
"get": {
40344177
"operationId": "messages_list",
@@ -5718,6 +5861,11 @@
57185861
"type": "integer",
57195862
"nullable": true,
57205863
"description": "Maximum number of recipients per message for this domain."
5864+
},
5865+
"max_recipients": {
5866+
"type": "string",
5867+
"nullable": true,
5868+
"description": "Maximum recipients per period (format: 'number/period', e.g., '500/d' for 500 per day)."
57215869
}
57225870
},
57235871
"nullable": true,
@@ -6210,6 +6358,11 @@
62106358
"type": "integer",
62116359
"nullable": true,
62126360
"description": "Maximum number of recipients per message for this mailbox."
6361+
},
6362+
"max_recipients": {
6363+
"type": "string",
6364+
"nullable": true,
6365+
"description": "Maximum recipients per period (format: 'number/period', e.g., '500/d' for 500 per day)."
62136366
}
62146367
},
62156368
"nullable": true,
@@ -7286,6 +7439,51 @@
72867439
"updated_at"
72877440
]
72887441
},
7442+
"RecipientQuota": {
7443+
"type": "object",
7444+
"description": "Serializer for recipient quota status.",
7445+
"properties": {
7446+
"period": {
7447+
"type": "string",
7448+
"description": "The quota period type (d=day, m=month, y=year)"
7449+
},
7450+
"period_display": {
7451+
"type": "string",
7452+
"description": "Human-readable period name"
7453+
},
7454+
"period_start": {
7455+
"type": "string",
7456+
"format": "date-time",
7457+
"description": "Start of the current quota period"
7458+
},
7459+
"recipient_count": {
7460+
"type": "integer",
7461+
"description": "Number of recipients sent during this period"
7462+
},
7463+
"quota_limit": {
7464+
"type": "integer",
7465+
"description": "Maximum number of recipients allowed during this period"
7466+
},
7467+
"remaining": {
7468+
"type": "integer",
7469+
"description": "Number of remaining recipients that can be sent to"
7470+
},
7471+
"usage_percentage": {
7472+
"type": "number",
7473+
"format": "double",
7474+
"description": "Percentage of quota used (0-100)"
7475+
}
7476+
},
7477+
"required": [
7478+
"period",
7479+
"period_display",
7480+
"period_start",
7481+
"quota_limit",
7482+
"recipient_count",
7483+
"remaining",
7484+
"usage_percentage"
7485+
]
7486+
},
72897487
"ResetPasswordError": {
72907488
"type": "object",
72917489
"properties": {

0 commit comments

Comments
 (0)