I have Postfix + BitDefender FRAMS running as hygiene gateway before few Exchanges.
BD FRAMS can learn it's Baesian filter by download SPAM and HAM emails from dedicated mailboxes.
Because we have sustain flow of SPAM to unknown recipients, I have idea to redirect this useful source of SPAM emails directly to SPAM-learning mailbox.
My configs:
main.cf:
myhostname = posfix.example.com
smtpd_banner = $myhostname
#myorigin = example.com
mydestination =
local_recipient_maps =
#virtual_alias_maps = hash:/etc/postfix/virtual
local_transport = error:local mail delivery is disabled
mynetworks = /etc/postfix/mynetworks
smtpd_use_tls = yes
#smtpd_tls_auth_only = yes
smtpd_tls_key_file = /etc/ssl/certs/posfix.example.com.pem
smtpd_tls_cert_file = /etc/ssl/certs/posfix.example.com.pem
smtpd_tls_CApath = /etc/ssl/certs
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
relay_domains = mysql:/etc/postfix/relay_domains
transport_maps = mysql:/etc/postfix/transport
relay_recipient_maps = mysql:/etc/postfix/relay_recipient_maps
show_user_unknown_table_name = no
unknown_local_recipient_reject_code = 550
mailbox_size_limit = 102400000000
message_size_limit = 102400000
smtpd_delay_reject = yes
smtpd_helo_required = yes
#smtpd_helo_restrictions =
# permit_mynetworks
# reject_invalid_hostname
# permit
smtpd_restriction_classes = verify_sender
verify_sender =
reject_unverified_sender
smtpd_sender_restrictions =
permit_mynetworks
smtpd_recipient_restrictions =
reject_unknown_recipient_domain
reject_non_fqdn_recipient
permit_mynetworks
reject_authenticated_sender_login_mismatch
reject_unauth_destination
check_recipient_access hash:/etc/postfix/recipient_access
check_sender_access hash:/etc/postfix/sender_access
#check_helo_access pcre:/etc/postfix/helo_access
reject_non_fqdn_sender
reject_unknown_sender_domain
reject_unlisted_sender
reject_invalid_hostname
reject_unauth_pipelining
check_sender_mx_access cidr:/etc/postfix/sender_mx_access
#reject_non_fqdn_hostname
#reject_unverified_sender
#reject_multi_recipient_bounce
permit
#smtpd_data_restrictions =
#reject_multi_recipient_bounce
# Added by BitDefender on Mon Nov 3 15:27:43 EET 2014
smtpd_milters=unix:/var/spool/postfix/BitDefender/bdmilterd.sock
milter_protocol = 2
milter_default_action = tempfail
milter_connect_timeout = 30s
milter_command_timeout = 30s
milter_content_timeout = 30s
# End of added lines
/etc/postfix/relay_domains:
user = postfix
password = postfix
dbname = postfix
query = SELECT name FROM relay_domains WHERE name='%s'
/etc/postfix/transport:
user = postfix
password = postfix
dbname = postfix
query = SELECT nexthop FROM relay_domains WHERE name='%s'
/etc/postfix/relay_recipient_maps:
user = postfix
password = postfix
dbname = postfix
query = SELECT email FROM relay_users WHERE email='%s'
my script for fill relay-users from AD (kindly share for you) for cron:
#!/usr/bin/python
__author__ = 'tiv'
import ldap
import MySQLdb
connections = {
1: ['dc.example.com', # AD domain controller
'EXAMPLE\\user', # AD user
'password', # AD user password
'dc=example, dc=local', # AD root DN
'mail.example.com'], # Exchange server
2: ['dc.example1.com', # AD domain controller
'EXAMPLE1\\user', # AD user
'password', # AD user password
'dc=example1, dc=local', # AD root DN
'mail.example1.com'], # Exchange server
#3: 'dc.example2.com', # AD domain controller
# 'EXAMPLE2\\user', # AD user
# 'password', # AD user password
# 'dc=example2, dc=local', # AD root DN
# 'mail.example2.com'], # Exchange server
}
mysql = ['localhost', # host
'postfix', # user
'postfix', # password
'postfix'] # schema
def main():
try:
emails = []
domains = []
for i in connections:
connection = connections[i]
print('Processing LDAP server ' + connection[0] + ':')
basedn = connections[i][3]
nexthop = connections[i][4]
lc = ldapconnection(connection)
ls = ldapsearch(lc, basedn)
rl = resultlist(ls)
emails.extend(rl[0])
for domain in rl[1]:
domains.append([domain, nexthop])
print('Processing of LDAP server ' + connection[0] + ' completed.')
createdb(emails, domains, mysql)
print('Operation completed successfully!')
except:
print('Error processing of LDAP server ' + connection[0] + '!')
pass
def ldapconnection(ldapserver):
try:
print(' Trying to connect to LDAP server ' + ldapserver[0] + '...')
ldapconnection = ldap.initialize('ldap://' + ldapserver[0])
ldapconnection.simple_bind_s(ldapserver[1], ldapserver[2])
ldapconnection.protocol_version = ldap.VERSION3
ldapconnection.set_option(ldap.OPT_REFERRALS, 0)
print(' Connection to LDAP server ' + ldapserver[0] + ' succesfull.')
except:
print('Error connecting to LDAP server ' + ldapserver[0] + '!')
pass
return ldapconnection
def ldapsearch(ldapconnection, basedn):
try:
print(' Sending LDAP query request...')
scope = ldap.SCOPE_SUBTREE
filter = '(&(proxyAddresses=smtp:*)(!(objectClass=contact)))'
attributes = ['proxyAddresses']
searchresults = ldapconnection.search_s(basedn, scope, filter, attributes)
print(' LDAP query request results received.')
except:
print('Error sending LDAP query request!')
pass
return searchresults
def resultlist(searchresults):
try:
print(' Processing LDAP query results...')
emails = []
domains = []
for i in range(len(searchresults)):
try:
for j in range(len(searchresults[i][1]['proxyAddresses'])):
r = searchresults[i][1]['proxyAddresses'][j].lower()
if 'smtp:' in r:
email = r[5:]
emails.append(email)
domain = email.split("@")[1]
domains.append(domain)
except:
pass
print(' LDAP query results processed.')
except:
print('Error processing LDAP query results!')
pass
return removedublicates(emails), removedublicates(domains)
def createdb(emails, domains, mysql):
try:
print('Connecting to DB ' + mysql[3] + '...')
try:
db = MySQLdb.connect(host=mysql[0], user=mysql[1], passwd=mysql[2])
cursor = db.cursor()
sql = 'CREATE SCHEMA IF NOT EXISTS ' + mysql[3]
cursor.execute(sql)
db.commit()
except:
pass
try:
db = MySQLdb.connect(host=mysql[0], user=mysql[1], passwd=mysql[2], db=mysql[3])
cursor = db.cursor()
except:
print('Error connecting to DB ' + mysql[3] + '!')
print(' Check schemas and tables...')
sql = ['CREATE TABLE IF NOT EXISTS ' + mysql[3] + '.relay_users (id INT NOT NULL, email LONGTEXT NULL, PRIMARY KEY (id))',
'CREATE TABLE IF NOT EXISTS ' + mysql[3] + '.relay_domains (id INT NOT NULL, name LONGTEXT NULL, nexthop LONGTEXT NULL, PRIMARY KEY (id))',
'TRUNCATE ' + mysql[3] + '.relay_users',
'TRUNCATE ' + mysql[3] + '.relay_domains']
for i in range(len(sql)):
cursor.execute(sql[i])
db.commit()
print(' Inserting domains...')
for i in range(len(domains)):
sql = 'INSERT INTO postfix.relay_domains (id, name, nexthop)' \
'VALUES ("' + str(i) + '", "' + domains[i][0] + '", "smtp:[' + domains[i][1] + ']")'
cursor.execute(sql)
db.commit()
print(' Inserting emails...')
for i in range(len(emails)):
sql = 'INSERT INTO postfix.relay_users (id, email)' \
'VALUES ("' + str(i) + '", "' + emails[i] + '")'
cursor.execute(sql)
db.commit()
db.close()
print('Connection to DB ' + mysql[3] + ' closed.')
except:
print('Error while operating with DB ' + mysql[3] + '!')
pass
def removedublicates(input):
seen = set()
seen_add = seen.add
return [x for x in input if not (x in seen or seen_add(x))]
if __name__ == '__main__':
main()
If somebody know, how to do this, I will appreciated.
Thanks.
Best Answer
Your request is bit complicated because this matter. Postfix, by design, will execute something based on positive result from maps. For example in your
transport_maps
, it will send email to specific host if the recipient has positive result from maps lookup. But, you want to execute something - redirect to another mailbox - if there is negative result from yourrelay_recipient_maps
lookup. With your maps type is hash, I think there are no other way unless involving sql/tcp map for implementing negative result logic in the map.For sql solution, here is the idea:
In this example I'll use sqlite. Suppose that you have table with one column named relay_recipient. Now the query
will return
mailboxspam@example.com
whenever the recipient doesn't exist in relay_recipient_maps. Place those maps onvirtual_alias
parameter. Then whenever the email sent to unknown user, then it will be aliased to mailboxspam@example.com