How postfix/transport works: writing my own transport

Red Squirrel

No Lifer
May 24, 2003
68,818
12,802
126
www.anyf.ca
I want to write my own postfix transport as I can't find much information online on what I need to do. I need to be able to have full control over what happens to mail on a per mailbox basis. (Virtual users) Some mail is spam filtered and then spam is put in a folder. some mail is spam filtered and then forwarded to another email, some mail is not spam filtered but put through a custom app etc etc...

So I just want to write my own custom transport that will handle all of this. Probably going to use C++.

I am looking for information on what the requirements are for this, such as what the various parameters in master.cf are, how the transport should handle the mail, what environment variables that are available, how to write to Maildir etc etc...

Where could I find this information? I've searched for weeks and can't find anything whatsoever. Any help would be appreciated. In fact, Postfix/dovecot documentation as a whole is rather scarce. It's one of the reasons I just want to write my own system, as the existing solutions like sieve that MIGHT do what I need barely have proper documentation. Not enough details are provided.
 

Gryz

Golden Member
Aug 28, 2010
1,551
204
106
A quick Google reveals that PostFix seems to be well documented:
http://www.postfix.org/documentation.html

Is that documentation you are talking about ? Is it not good enough ?
E.g. here is a list of all parameters in the main.cf file:
http://www.postfix.org/postconf.5.html
(Or is main.cf different from master.cf ? I don't know PostFix, sorry).
Maybe one of these topics is helpful: http://www.postfix.org/docs.html ?

And if the documentation is really not sufficient, you can always "Use the Source, Luke" !!
http://www.postfix.org/download.html
 

Red Squirrel

No Lifer
May 24, 2003
68,818
12,802
126
www.anyf.ca
Yeah those docs don't really talk about the specifics, like if I want to have rules/actions on a per virtual mailbox basis. Though part of the issue with setting up mail is that it involves so many different progams that tie into each other. Postfix, dovecot, procmail, etc..

But yeah I might just go through the source and try to understand it that way. In fact I might be able to just modify it so that it can read a .procmailrc file in virtual directories, then still use procmail. Though if I write my own transport it makes it easier to integrate, so probably will go with that. I can probably reuse some of the existing postfix code too such as how to write to the maildir.
 

Red Squirrel

No Lifer
May 24, 2003
68,818
12,802
126
www.anyf.ca
Ok think I'm getting somewhere, basic crude test program:

Code:
#include <iostream>
#include <fstream>
#include <string.h>
#include <stdio.h>

using namespace std;

int main()
{
string email="";

char a=' ';

while(true)
{
   a = getchar();
   
   if(a==EOF)break;

   email+=a;
}


fstream fout("/localdata/mail/vmailbox/rohan.loc/test/cur/ThisIsTotallyNotValidFormat.txt",ios::out);

fout<<email;

fout.close();

    return 0;
}



Master.cf line:
Code:
customtspt   unix - n n - - pipe
  flags=DRhu user=vmail:vmail argv=/localdata/apps/customtspt/customtspt

And changed virtual_transport to customtspt. I'll probably come up with a better name than that but just testing for now.

At this point any mail sent to any valid email address gets put in the test@rohan.loc inbox, and I can open it. I even tested an attachement. So I'm off to a good start, at least I got the very basic conceptual stuff working.

Now to make sure it goes to the right mailbox, what is the best way to determine the email it's addressed to, do I actually parse out and find the From field, or is there some kind of variable that gets passed or something?

Obviously I'll have to use the proper Maildir format too, but from the looks of it you can actually get away with pretty much anything, but I'll still follow the proper standard. I found a doc that explains it well here:

http://cr.yp.to/proto/maildir.html


Also I was going through the Postfix source but it could take days if weeks to try to decipher everything and get familiarized with the code, it's always harder to read someone else's code and know what's going on at a glance as everyone has their own style. That said, is there a way I can find out what the flags mean in the master.conf file? Like "flags=DRhu" specifically.

I just copied the ones from another program, but I rather actually understand what they do instead of blindly put stuff and assume that just because it works, it works right.

So far this seems simple enough though, it's just something that does not seem to be all that well documented on how to do so kinda have to figure it out as I go.
 

matricks

Member
Nov 19, 2014
194
0
0
So I just want to write my own custom transport that will handle all of this. Probably going to use C++.

I noticed you already decided and started out, but I thought I'd post this anyway. Have you looked at transport tables? It seems the case you want to solve is to map your different addresses to the transport you want to use for each of them. Transport tables seem to do just that.

I've only toyed around with Postfix, but isn't a delivery transport one specific way of handling a message? So for your listed use cases, you would have transports pseudo-defined as spamToFolder, spamToForward, sendToCustomApp and so on (assuming spam filtering is done by Postfix transports through e.g. SpamAssassin, if procmail calls the filtering you wouldn't have these). Implementing one transport to rule them all, and handling your various addresses there seems to break with Postifx logic. Which is fine as long as you are aware that you are doing it, and this is the big point I want to make.

How I see it, delivery transports shouldn't handle messages conditionally - they should take the message, do what they say they do, then deliver it where they're supposed to. E.g. a spam filter transport will take the message, mark it as spam, ham or unsure, and hand it on to whatever is the next transport in line before the message ends up in a mailbox. The spam transport should not look at the address and decide "I shouldn't mark this at all" based on what the address is. Unless the transport is involved in actually delivering the mail to its mailbox or relay, the transport shouldn't care what the address is.
 

Red Squirrel

No Lifer
May 24, 2003
68,818
12,802
126
www.anyf.ca
I had thought of that actually, but it's not as granular as if I just have rules per mailbox. As I actually WANT to be able to decide on a per mailbox bassis if it even does go through the spam filter, how/if it's marked etc, virus scan, or any other possible thing I may add. For example speciality local mailboxes wont even go through virus scan, as it's just a waste of resources. So basically this custom transport will be responsible for everything that happens to the mail, and the settings to configure that will be all in one spot. Technically if I really want to I can even have several different email addresses that, based on conditions, put mail in a completely different mailbox and/or folder. I'm going to make this as flexible as possible.