Last active
July 7, 2016 14:15
-
-
Save noah/468696a5862d19463dd32f3a5e5347b2 to your computer and use it in GitHub Desktop.
Programmatically add entries to postfix sender_access file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
import sys | |
import smtplib | |
from subprocess import call | |
from email.parser import Parser | |
from email.utils import parseaddr, make_msgid | |
from email.mime.text import MIMEText | |
from email.mime.multipart import MIMEMultipart | |
# BlockSpammer.py <[email protected]> | |
# | |
# MIT license. | |
# | |
# Receive an message which contains a forwarded message and (optionally) a | |
# supplied block message. Parse the forwarded email, extracting recipient and | |
# a list of email addresses to block. Update the Postfix configuration to | |
# block those addresses. Email the original recipient back, letting her know | |
# those addresses are in fact blocked. | |
# | |
# | |
# Needs: | |
# smtpd_recipient_restrictions = | |
# check_recipient_access hash:/etc/postfix/recipient_access | |
# | |
# containing minimally: | |
# tehblockaddressss@mydomain FILTER blockspammer:dummy | |
# | |
# and | |
# blockspammer unix - n n - - pipe flags=D user=someuser argv=/usr/bin/sudo /path/to/BlockSpammer.py | |
# | |
# and | |
# tehblockaddressss needs to be in /etc/postfix/aliases | |
msg = Parser().parse(sys.stdin) | |
msg_from = msg['From'] | |
# collection of addresses to block | |
block = set() | |
# default block message for postfix sender_access REJECT block | |
block_message = 'blocked' | |
for part in msg.walk(): | |
# print part.get_content_type(), '*'*80; print part | |
# multiparts are just containers | |
if part.get_content_maintype() == 'multipart': continue | |
if part.get_content_type() == 'message/rfc822': # it's a forwarded message | |
fmsg = part.get_payload()[0] | |
# who the forwarded message was ultimately addressed to | |
real_recipient = fmsg['Delivered-To'] | |
for h in ['From', 'Return-Path']: | |
a = parseaddr(fmsg[h])[1] | |
if a: block.add(a) | |
# MUST break so that additional parts sent by the spammer will not be | |
# processed. NB this relies on parts being ordered .... ;[ | |
break | |
else: # it's a message body from me | |
# override the default (uh oh, found a spammer we really don't like) | |
block_message = part.get_payload() | |
block = list(block) | |
# print 'to', real_recipient | |
# print 'block', list(block) | |
# print 'message', block_message | |
# now add to the postfix block list | |
blocked = [] | |
BLOCKFILE='/etc/postfix/sender_access' | |
with open(BLOCKFILE, 'a') as blockfile: | |
for e in block: | |
assert "mydomain" not in e | |
# this works with pcre:/ type tables. change the string format for something else | |
blockfile.write('/{}/\t\tREJECT {}.\n'.format(e, block_message)) | |
blocked.append(e) | |
# update the postfix map | |
call(["/usr/bin/postmap", BLOCKFILE]) | |
# reply to the complaining email | |
outer = MIMEMultipart("mixed") | |
rmsg = MIMEText( | |
'blocked:\n\t{}\nmessage:\n\t{}'.format('\n\t'.join(blocked), block_message), "plain") | |
rmsg["Message-ID"] = make_msgid() | |
rmsg["In-Reply-To"] = fmsg["Message-ID"] | |
rmsg["References"] = fmsg["Message-ID"] | |
rmsg["Subject"] = "Re: "+ fmsg["Subject"] | |
rmsg["To"] = real_recipient | |
rmsg["From"] = "tehblockaddressss@mydomain" | |
outer.attach(rmsg) | |
outer.attach(fmsg) | |
s = smtplib.SMTP('localhost') | |
s.sendmail("me@mydomain", [real_recipient], rmsg.as_string()) | |
s.quit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment