There is always a well working, prepared, documented and good way to solve a problem. The problem with that is that in the most cases we end up with a rat tail of components, we cannot install, maintain or want.
The real solution can be found here:
https://dokuwiki.nausch.org/doku.php/centos:mail_c7:spam_11 https://github.com/roehling/postsrsd/
It sounds very simple to implement working srs with Postfix. There is a tool set to perform this task. My only problem was that it was over engeneered to my understanding of the problem I found and liked to solve.
Make things easier for me and not for others, was my goal. So simple Python hack was my choice.
Postfix has a simple communication protocol to have TCP backed maps in place.
# Postfix asks for it
< get localpart@domain.com
# You reply with the new address
> 200 new-localpart@domain.com
There might also be the case, that you cannot lookup or have an error.
# Postfix asks for it
< get localpart@domain.com
# You reply with an error code and the original address
> 400 localpart@domain.com
This is simple to implement and with utilizing some other modules like the hashlib to generate a salted hash it's robust.
"""Server to provide address encoding for simplified SRS"""
import SocketServer
import hashlib, base64
MY_DOMAIN='example.com'
SECRET='Who does know me?'
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
self.data=self.data.replace('get ','')
if self.data.endswith(MY_DOMAIN):
return self.request.send('200 {0}\n'.format(self.data))
if self.data.strip() == '""':
return self.request.send('200 {0}\n'.format(self.data))
if '@' not in self.data:
return self.request.send('400 {0}\n'.format(self.data))
d=hashlib.md5(b"{0}{1}".format(SECRET, self.data)).digest(); d=base64.b64encode(d);
return self.request.send('200 {0}#{1}@{2}\n'.format(self.data.replace('@','-at-'), d, MY_DOMAIN))
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
SocketServer.TCPServer.allow_reuse_address = True
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
And to convert everything back the following was the way to go.
"""Server to provide address decoding for simplified SRS"""
import SocketServer
import hashlib, base64
MY_DOMAIN='example.com'
SECRET='Who does know me?'
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
self.data=self.data.replace('get ','')
if self.data.endswith('@{0}'.format(MY_DOMAIN)):
if '#' in self.data and '-at-' in self.data:
orig=self.data.split('#',1)[0].replace('-at-','@')
orighash=self.data.split('#',1)[1].split('@',1)[0]
d=hashlib.md5(b"{0}{1}".format(SECRET, orig)).digest(); d=base64.b64encode(d);
if d == orighash:
return self.request.send('200 {0}\n'.format(orig))
return self.request.send('200 {0}\n'.format(self.data))
return self.request.send('200 {0}\n'.format(self.data))
if __name__ == "__main__":
HOST, PORT = "localhost", 9998
SocketServer.TCPServer.allow_reuse_address = True
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
In order to make it play nice with Postfix you need to enable the lookup via TCP socket there.
# main.cf
recipient_canonical_maps = tcp:127.0.0.1:9998
recipient_canonical_classes = envelope_recipient
sender_canonical_maps = tcp:127.0.0.1:9999
sender_canonical_classes = envelope_sender
# master.cf
smtp inet n - - - - smtpd
-o sender_canonical_maps=tcp:127.0.0.1:9999
-o sender_canonical_classes=envelope_sender
With that the emails are encoded and decoded in and out.