diff --git a/core/admin/mailu/configuration.py b/core/admin/mailu/configuration.py
index d2d34d88..c1016949 100644
--- a/core/admin/mailu/configuration.py
+++ b/core/admin/mailu/configuration.py
@@ -46,6 +46,7 @@ DEFAULT_CONFIG = {
'DKIM_SELECTOR': 'dkim',
'DKIM_PATH': '/dkim/{domain}.{selector}.key',
'DEFAULT_QUOTA': 1000000000,
+ 'MESSAGE_RATELIMIT': '200/day',
# Web settings
'SITENAME': 'Mailu',
'WEBSITE': 'https://mailu.io',
diff --git a/core/admin/mailu/internal/views/postfix.py b/core/admin/mailu/internal/views/postfix.py
index c358c37f..811dd4c0 100644
--- a/core/admin/mailu/internal/views/postfix.py
+++ b/core/admin/mailu/internal/views/postfix.py
@@ -1,5 +1,6 @@
-from mailu import models
+from mailu import models, utils
from mailu.internal import internal
+from flask import current_app as app
import flask
import idna
@@ -31,7 +32,6 @@ def postfix_alias_map(alias):
destination = models.Email.resolve_destination(localpart, domain_name)
return flask.jsonify(",".join(destination)) if destination else flask.abort(404)
-
@internal.route("/postfix/transport/{% trans %}User settings{% endtrans %}
{% trans %}Email{% endtrans %}
{% trans %}Features{% endtrans %}
- {% trans %}Quota{% endtrans %}
+ {% trans %}Storage Quota{% endtrans %}
+ {% trans %}Sending Quota{% endtrans %}
{% trans %}Comment{% endtrans %}
{% trans %}Created{% endtrans %}
{% trans %}Last edit{% endtrans %}
@@ -41,6 +42,8 @@
{% if user.enable_pop %}pop3{% endif %}
{{ user.quota_bytes_used | filesizeformat }} / {{ (user.quota_bytes | filesizeformat) if user.quota_bytes else '∞' }}
+ {% set limiter = user.sender_limiter %}
+ {{ limiter.get_window_stats()[1] }} / {{ limiter.limit }}
{{ user.comment or '-' }}
{{ user.created_at }}
{{ user.updated_at or '' }}
diff --git a/core/postfix/conf/main.cf b/core/postfix/conf/main.cf
index a35ca16c..3d23bec2 100644
--- a/core/postfix/conf/main.cf
+++ b/core/postfix/conf/main.cf
@@ -101,6 +101,8 @@ smtpd_sender_login_maps = ${podop}senderlogin
# Restrictions for incoming SMTP, other restrictions are applied in master.cf
smtpd_helo_required = yes
+check_ratelimit = check_sasl_access ${podop}senderrate
+
smtpd_client_restrictions =
permit_mynetworks,
check_sender_access ${podop}senderaccess,
diff --git a/core/postfix/conf/master.cf b/core/postfix/conf/master.cf
index e45a8ccf..15613476 100644
--- a/core/postfix/conf/master.cf
+++ b/core/postfix/conf/master.cf
@@ -7,7 +7,8 @@ smtp inet n - n - - smtpd
# Internal SMTP service
10025 inet n - n - - smtpd
-o smtpd_sasl_auth_enable=yes
- -o smtpd_client_restrictions=reject_unlisted_sender,reject_authenticated_sender_login_mismatch,permit
+ -o smtpd_discard_ehlo_keywords=pipelining
+ -o smtpd_client_restrictions=$check_ratelimit,reject_unlisted_sender,reject_authenticated_sender_login_mismatch,permit
-o smtpd_reject_unlisted_recipient={% if REJECT_UNLISTED_RECIPIENT %}{{ REJECT_UNLISTED_RECIPIENT }}{% else %}no{% endif %}
-o cleanup_service_name=outclean
outclean unix n - n - 0 cleanup
diff --git a/core/postfix/start.py b/core/postfix/start.py
index df290a3a..4c291061 100755
--- a/core/postfix/start.py
+++ b/core/postfix/start.py
@@ -26,7 +26,8 @@ def start_podop():
("recipientmap", "url", url + "recipient/map/§"),
("sendermap", "url", url + "sender/map/§"),
("senderaccess", "url", url + "sender/access/§"),
- ("senderlogin", "url", url + "sender/login/§")
+ ("senderlogin", "url", url + "sender/login/§"),
+ ("senderrate", "url", url + "sender/rate/§")
])
def is_valid_postconf_line(line):
diff --git a/docs/webadministration.rst b/docs/webadministration.rst
index 86ce41c0..03b07ba2 100644
--- a/docs/webadministration.rst
+++ b/docs/webadministration.rst
@@ -315,6 +315,21 @@ This page is also accessible for domain managers. On the users page new users ca
* Fetched accounts. Access the fetched accounts page of the user. See the :ref:`fetched accounts page
/ day +
+