- [Show page]
- [Old revisions]
- [[unknown link type]]
- []
Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
linux:apache:sendmail_python [2017/02/16 16:04] vondra [Code] |
linux:apache:sendmail_python [2017/02/21 14:27] (current) tomsa [Code] |
||
---|---|---|---|
Line 2: | Line 2: | ||
Sendmail wrapper limiting amount of emails sent by php | Sendmail wrapper limiting amount of emails sent by php | ||
===== Installation ===== | ===== Installation ===== | ||
+ | * <code bash>pip install psutils</code> | ||
* Copy the script below into /usr/sbin/safe_sendmail | * Copy the script below into /usr/sbin/safe_sendmail | ||
- | * Put the path to script into sendmail_path variable in php.ini | + | * Put the path to script into sendmail_path variable in php.ini or into /etc/php5/fpm/pool.d/www.conf if using php-fpm |
- | * Database and log files will be created in /tmp/safe_sendmail.db and /tmp/safe_sendmail.log respectively | + | * <code>php_admin_value[sendmail_path] = /usr/sbin/safe_sendmail</code> |
+ | * Database and log files will be created in workdir defined in script ("/usr/local/safe_sendmail/") this dir should be writable for everyone (limited access could lead to unexpected bahaviour) | ||
* Timewindow (default 1 hour) and treshold (default 200 emails) parameters are declared in script | * Timewindow (default 1 hour) and treshold (default 200 emails) parameters are declared in script | ||
+ | * For deeper inspection of mail traffic uncomment logging lines at the end (logging the mail body) | ||
===== Testing ===== | ===== Testing ===== | ||
- | * Put following content in /var/www/testmail.txt: (few blank lines may be needed at the end of the file)<code file> | + | * Put following content in /tmp/testmail.txt: (few blank lines may be needed at the end of the file)<code file> |
To: firma@starlab.cz | To: firma@starlab.cz | ||
Subject: This is a test message subject | Subject: This is a test message subject | ||
Line 19: | Line 21: | ||
</code> | </code> | ||
- | * Run:<code bash>for i in `seq 1 300`; do cat /var/www/testmail.txt | safe_sendmail firma@starlab.cz ; done</code> | + | * Run:<code bash>for i in `seq 1 300`; do cat /tmp/testmail.txt | safe_sendmail firma@starlab.cz ; done</code> |
- | * Observe log file:<code bash>tail -f /tmp/safe_sendmail</code> | + | * Observe log file:<code bash>tail -f /usr/local/safe_sendmail/safe_sendmail.log</code> |
* After the treshold number of emails script refuses to send more emails. | * After the treshold number of emails script refuses to send more emails. | ||
Line 57: | Line 59: | ||
time_scope = 60 | time_scope = 60 | ||
+ | notification_mail = """To: firma@starlab.cz | ||
+ | Subject: Alert! Too many outgoing emails from server {server_name} | ||
+ | |||
+ | Safe sendmail script started filtering messages on server {server_name}. Threshold reached. | ||
+ | """.format(server_name='webhosting.starlab.cz') | ||
+ | |||
def check_db(): | def check_db(): | ||
Line 64: | Line 72: | ||
is_table = len(c.fetchall()) | is_table = len(c.fetchall()) | ||
if is_table == 0: | if is_table == 0: | ||
- | c.execute("CREATE TABLE mails (date text, address_to text)") | + | c.execute("CREATE TABLE mails (date text, address_to text, spamcount integer)") |
conn.commit() | conn.commit() | ||
return True | return True | ||
Line 95: | Line 103: | ||
logger.debug("Datetime: %s" % timestamp) | logger.debug("Datetime: %s" % timestamp) | ||
past = timestamp - dt.timedelta(minutes=time_scope) | past = timestamp - dt.timedelta(minutes=time_scope) | ||
- | with sqlite3.connect(db_file) as conn: | + | with sqlite3.connect(db_file) as conn: |
c = conn.cursor() | c = conn.cursor() | ||
- | c.execute('INSERT INTO mails VALUES(?,?)', (timestamp, address)) | + | c.execute('SELECT spamcount FROM mails ORDER BY date DESC LIMIT 1') |
- | conn.commit() | + | last_spam_count = c.fetchone()[0] |
+ | if last_spam_count is None: | ||
+ | last_spam_count = 0 | ||
c.execute('SELECT COUNT(*) FROM mails where date > ?', (past,)) | c.execute('SELECT COUNT(*) FROM mails where date > ?', (past,)) | ||
- | count_since_past = c.fetchone()[0] | + | count_since_past = c.fetchone()[0] + 1 |
logger.debug("Count since %s %d" % (timestamp, count_since_past)) | logger.debug("Count since %s %d" % (timestamp, count_since_past)) | ||
+ | c.execute('INSERT INTO mails VALUES(?,?,?)', (timestamp, address, count_since_past)) | ||
+ | conn.commit() | ||
if count_since_past < threshold: | if count_since_past < threshold: | ||
if send_mail(mail): | if send_mail(mail): | ||
Line 108: | Line 121: | ||
sys.exit(2) | sys.exit(2) | ||
else: | else: | ||
- | # logger.info("Parent: {}".format(parent_process.cmdline())) # uncomment to get parent's cmdline | + | if last_spam_count < threshold: |
+ | send_mail(notification_mail) | ||
+ | # logger.info("Parent: {}".format(parent_process.cmdline())) # uncomment to get parent's cmdline | ||
# logger.info("Grandparent: {}".format(grandparent_process.cmdline())) # uncomment to get grandparent's cmdline | # logger.info("Grandparent: {}".format(grandparent_process.cmdline())) # uncomment to get grandparent's cmdline | ||
- | # logger.info(mail) # uncomment to get raw input (mail content and headers) | + | # logger.info(mail) # uncomment to get raw input (mail content and headers) |
logger.warning("Unable to send mail to address %s - quota exceeded! (%d mails sent in last %d minutes - limit %s)" % (address, count_since_past, time_scope, threshold)) | logger.warning("Unable to send mail to address %s - quota exceeded! (%d mails sent in last %d minutes - limit %s)" % (address, count_since_past, time_scope, threshold)) | ||
sys.exit(1) | sys.exit(1) | ||
- | |||
</code> | </code> | ||
linux/apache/sendmail_python.1487257456.txt.gz · Last modified: 2017/02/16 16:04 by vondra