limit outgoing
----------
Limit 100 e-mails per hour postfix
edit main.cf and set some sender limits:
anvil_rate_time_unit = 3600s
anvil_status_update_time = 600s
smtpd_recipient_limit = 100
smtpd_recipient_overshoot_limit = 101
smtpd_client_connection_rate_limit = 100
smtpd_client_message_rate_limit = 100
smtpd_client_recipient_rate_limit = 100
local_destination_concurrency_limit = 2
default_destination_concurrency_limit = 20
this will limit 100 mails per user per hour. A sender will have to wait for an hour before they can send out any more mails, if they reach limit of 100 e-mail.
Postfix - Rate limit for all domains
smtp_destination_rate_delay = 60s
default_destination_recipient_limit = 2
default_destination_concurrency_limit = 1
smtp_destination_concurrency_limit = 1
smtp_destination_recipient_limit = 2
smtp_initial_destination_concurrency = 1
Postfix: limit outgoing mail throttling
/etc/postfix/main.cf
smtp_destination_concurrency_limit = 2 smtp_destination_rate_delay = 1s smtp_extra_recipient_limit = 10
default_destination_concurrency_limit: This means that postfix will up to two concurrent connections per receiving domains. The default value is 20.
default_destination_rate_delay: Postfix will add a delay between each message to the same receiving domain. It overrides the previous rule and in this example, it will send one email after another with a delay of 1 second. If you want to disable this rule, either delete it or set to 0.
default_extra_recipient_limit: Limit the number of recipients of each message. If a message had 20 recipients on the same domain, postfix will break it out to two different email messages instead of one.
Then restart your Postfix.
2.1 Limit by domain
You can limit per domain if you want like this:
/etc/postfix/main.cf
transport_maps = hash:/etc/postfix/transport # Throttle limit policy mail (global) smtp_destination_concurrency_limit = 4 smtp_extra_recipient_limit = 2 # Polite policy polite_destination_concurrency_limit = 3 polite_destination_rate_delay = 0 polite_destination_recipient_limit = 5 # Turtle policy turtle_destination_concurrency_limit = 2 turtle_destination_rate_delay = 1s turtle_destination_recipient_limit = 2
Then add domains with the wished policy:
/etc/postfix/transport
gmail.com polite: yahoo.com polite: hotmail.com turtle: live.fr turtle: orange.fr turtle:
Edit master configuration to inform postfix of those config. Add those lines:
/etc/postfix/master.cf
polite unix - - n - - smtp turtle unix - - n - - smtp
Postmap and reload:
postmap /etc/postfix/transport service postfix reload
-------------
Ratelimit-policyd - MySQL
Installation
Recommended installation:
$ cd /opt/ $ git clone https://github.com/onlime/ratelimit-policyd.git ratelimit-policyd $ cd ratelimit-policyd $ chmod +x install.sh $ ./install.sh
Create the DB schema and user:
$ mysql -u root -p < mysql-schema.sql
GRANT USAGE ON *.* TO policyd@'localhost' IDENTIFIED BY '********'; GRANT SELECT, INSERT, UPDATE, DELETE ON policyd.* TO policyd@'localhost';
Adjust configuration options in daemon.pl:
### CONFIGURATION SECTIONmy @allowedhosts = ('127.0.0.1', '10.0.0.1'); my $LOGFILE = "/var/log/ratelimit-policyd.log"; my $PIDFILE = "/var/run/ratelimit-policyd.pid"; my $SYSLOG_IDENT = "ratelimit-policyd"; my $SYSLOG_LOGOPT = "ndelay,pid"; my $SYSLOG_FACILITY = LOG_MAIL; chomp( my $vhost_dir = `pwd`); my $port = 10032; my $listen_address = '127.0.0.1'; # or '0.0.0.0'my $s_key_type = 'email'; # domain or emailmy $dsn = "DBI:mysql:policyd:127.0.0.1"; my $db_user = 'policyd'; my $db_passwd = '************'; my $db_table = 'ratelimit'; my $db_quotacol = 'quota'; my $db_tallycol = 'used'; my $db_updatedcol = 'updated'; my $db_expirycol = 'expiry'; my $db_wherecol = 'sender'; my $deltaconf = 'daily'; # hourly|daily|weekly|monthlymy $defaultquota = 1000; my $sql_getquota = "SELECT $db_quotacol, $db_tallycol, $db_expirycol FROM $db_table WHERE $db_wherecol = ? AND $db_quotacol > 0"; my $sql_updatequota = "UPDATE $db_table SET $db_tallycol = $db_tallycol + ?, $db_updatedcol = NOW(), $db_expirycol = ? WHERE $db_wherecol = ?"; my $sql_updatereset = "UPDATE $db_table SET $db_tallycol = ?, $db_updatedcol = NOW(), $db_expirycol = ? WHERE $db_wherecol = ?"; my $sql_insertquota = "INSERT INTO $db_table ($db_wherecol, $db_quotacol, $db_tallycol, $db_expirycol) VALUES (?, ?, ?, ?)"; ### END OF CONFIGURATION SECTION
Take care of using a port higher than 1024 to run the script as non-root (our init script runs it as user "postfix").
In most cases, the default configuration should be fine. Just don't forget to paste your DB password in $db_password.
Now, start the daemon:
$ service ratelimit-policyd start
Testing
Check if the daemon is really running:
$ netstat -tl | grep 10032 tcp 0 0 localhost.localdo:10032 *:* LISTEN $ cat /var/run/ratelimit-policyd.pid 30566 $ ps aux | grep daemon.pl postfix 30566 0.4 0.1 176264 19304 ? Ssl 14:37 0:00 /opt/send_rate_policyd/daemon.pl $ pstree -p | grep ratelimit init(1)-+-/opt/ratelimit-(11298)-+-{/opt/ratelimit-}(11300) | |-{/opt/ratelimit-}(11301) | |-{/opt/ratelimit-}(11302) | |-{/opt/ratelimit-}(14834) | |-{/opt/ratelimit-}(15001) | |-{/opt/ratelimit-}(15027) | |-{/opt/ratelimit-}(15058) | `-{/opt/ratelimit-}(15065)
Print the cache content (in shared memory) with update statistics:
$ service ratelimit-policyd status Printing shm: Domain : Quota : Used : Expire Threads running: 6, Threads waiting: 2
Postfix Configuration
Modify the postfix data restriction class smtpd_data_restrictions like the following, /etc/postfix/main.cf:
smtpd_data_restrictions = check_policy_service inet:$IP:$PORT
sample configuration (using ratelimitpolicyd as alias as smtpd_data_restrictions does not allow any whitespace):
smtpd_restriction_classes = ratelimitpolicyd ratelimitpolicyd = check_policy_service inet:127.0.0.1:10032 smtpd_data_restrictions = reject_unauth_pipelining, ratelimitpolicyd, permit
If you're sure that ratelimit-policyd is really running, restart Postfix:
$ service postfix restart
Logging
Detailed logging is written to ``/var/log/ratelimit-policyd.log```. In addition, the most important information including the counter status is written to syslog:
$ tail -f /var/log/ratelimit-policyd.log Sat Jan 10 12:08:37 2015 Looking for demo@example.com Sat Jan 10 12:08:37 2015 07F452AC009F: client=4-3.2-1.cust.example.com[1.2.3.4], sasl_method=PLAIN, sasl_username=demo@example.com, recipient_count=1, curr_count=6/1000, status=UPDATE $ grep ratelimit-policyd /var/log/syslog Jan 10 12:08:37 mx1 ratelimit-policyd[2552]: 07F452AC009F: client=4-3.2-1.cust.example.com[1.2.3.4], sasl_method=PLAIN, sasl_username=demo@example.com, recipient_count=1, curr_count=6/1000, status=UPDATE
Postfix send rate limit per user/domain
I needed to limit the number of emails sent by users through your Postfix server, and store message quota in RDMS systems (maybe you have multiple MX).
I tried policyd or other policy daemons for Postfix; but they all miss support for SQL storage.
With this piece of code you can setup a send rate per users or sender domain on daily/weekly/monthly basis and store data in MySQL (PostgreSQL,…).
To work with mqdaemon you only need a mysql table described like this one:
CREATE TABLE `emails` (`email` VARCHAR(65) NOT NULL,`messagequota` INT(10) UNSIGNED NOT NULL DEFAULT '0',`messagetally` INT(10) UNSIGNED NOT NULL DEFAULT '0',`timestamp` INT(10) UNSIGNED DEFAULT NULL,)
and setup configuration parameters (db_table, db_wherecol, db_messagequota, etc) inside the Perl script.
You must insert all rows for the emails you have to enforce! The script is configured to use a simple UPDATE.
Modify the postfix data restriction class “smtpd_data_restrictions” like the following:
To print the cache content with update statistics for username into log file just send a SIGHUP to the process PID using “kill -HUP $pid” or invoke the script with printshm paramenter (perl ./daemon.pl printshm).
To enforce per-domain quota set the search key ($s_key_type parameter) to “domain”.
Start the daemon with “# ./daemon.pl” and kill it with “# pkill daemon.pl”.
Take care of using a port higher than 1024 to run the script as non-root.
This daemon caches the quota in memory, so you don’t need to worry about I/O operations.
-----------------
smtpd_data_restrictions = check_policy_service inet:$IP:$PORT