Postfix: how to reject incoming mail as in Sendmail's "error:nouser"?
Linux - ServerThis forum is for the discussion of Linux Software used in a server related context.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Either this is a typo, or is incorrect in your main.cf, but we can't debug inconsistent input/output and configuration. This is why it is necessary to show postconf -n and mail log lines relevant to the problem, when the problem occurs.
From your Edit 2: the virtual alias will map john to john@$myorigin if the default append_at_myorigin is set.
Again, repeat postconf -n, and log lines, which transcends language weakness. :-)
It would be best to leave your Sendmail concepts behind, and start learning to think in terms of how Postfix works.
I'm trying, I'm trying!
But it isn't easy. I went from Sendmail to Postfix because everybody told me it was so much easier to configure than Sendmail. So far it has turned out to be a lot more complicated - at least for the tasks I'm trying to accomplish.
That's me being confusing. But it's not a typo. In fact, it doesn't matter if it's a typo or not because the situation is the same for virtual domains and for mydestination domains.
Quote:
From your Edit 2: the virtual alias will map john to john@$myorigin if the default append_at_myorigin is set.
append_at_myorigin is set to "yes" (in fact, it isn't set at all so it's defaulting to "yes"). But it shouldn't matter if it's expanded or not.
I'll try to explain a bit better in a new message as to not make this even more confusing than it already is. so please bare with me.
Oh. and let me thank you again for taking the time helping this "noob"...
Goal
To handle mail for several users. Each user receives mail at several different virtual domains. Users only use virtual names in email addresses - never their *nix account names. Mail directed at specific addresses or users should be rejected - not bounced. Some mail needs to be redirected to another mailserver running on a non-standard port (10025) on a different machine.
Domains
As an example, I will use the following domain names (in reality, there are 45):
Code:
mydomain.com (main domain)
virtualdomain1.com (virtual domain)
virtualdomain2.com (virtual domain)
otherserver.com (the other mailserver)
*nix Account Names
As an example, I will use usernames like "User1", "User2", "User3" for existing *nix account names. All other names I use (like "NoSuchUser") in this example can be considered "non-existing".
postconf -n
This is the true output of postconf -n, but with my true domainnames and IP address replaced (they will be displayed in grey):
1) When I send an email to spam@mydomain.com, (or any other address that is redirected to NoSuchUser) the mail isn't rejected. Instead I receive a bounce mail:
This is not what I expect. I expect mail to user "NoSuchUser" to be caught by check_recipient_access hash:/etc/postfix/recipient_access.
2) When I send mail to NoSuchUser@mydomain.com The mail is rejected with the message "No such user here!" - as expected because it is properly caught by check_recipient_access hash:/etc/postfix/recipient_access. But when I send mail to junk@mydomain.com which is redirected to NoSuchUser@mydomain.com, it arrives in User3's mailbox (the catchall). This is not expected. I expect it to be rejected.
Possible Solutions
A) List every single mail address that should be rejected in recipient_access. This works but it's impractical since such a setup is prone to mistakes (you constantly need to cross-check recipient_access and virtusertable).
B) Use a pcre table. Slow (I think, since my virtusertable contains almost 400 entries) and impractical because it's cumbersome to list all email addresses which you want to reject if the domain has a catchall (some domains with a catchall have dozens of addresses that needs to be rejected). But in all honesty I haven't experimented with this yet. The advantage is however that you have everything in a single file.
My Question
(Finally!) So what is the proper way to do this? I would love to do it the way I propose above: redirect all mail that needs to be rejected to a single account (existing or non-existing) like "NoSuchUser" then set the action for this user to "REJECT". But I'm starting to suspect this isn't possible - or is it?
The sendmail binary does not perform SMTP - it drops mail into postfix's queue via pickup. There is no chance to reject. Rejection occurs only during SMTP conversations and sendmail has none. Postfix can only bounce in this case.
Sending mail to junk@mydomain.com - junk@mydomain.com rewrites to NoSuchUser@mydomain.com; this is done by the cleanup daemon, and is AFTER smtpd_*_checks, therefore it cannot be rejected by smtpd in the way you desire. junk@mydomain.com is a valid email address - you listed it, so it is accepted.
The problem you are having is that you want your cake and want to eat it too. You have a wildcard, which defeats recipient validation, so all recipients are considered valid by Postfix. You also want to invalidate some recipients in that wildcarded domain, but don't want to use the standard mechanisms, and want to do it after address rewriting, which is too late. If you want to wildcard, and want to list invalid recipients, you need to list all the recipients you want to be as invalid in an access table. If you feel this is prone to mistakes, that's what makefiles are for, or program a tool to populate your tables.
You will not notice any degradation in performance with a mere 400 recipients in a pcre table - this is a small installation. Again, generate the lists via some tool.
Postfix does not have a "virtual user table". It has address classes: local, virtual mailbox domains, virtual alias domains, relay domains. You are confusing Sendmail style virtual user tables with Postfix's virtual aliases and virtual alias domains. Furthermore, you have a file called local-host-names, which really is a list of virtual alias domains. This is confusing, because of the aforementioned address class name of "local" (vs. virtual alias domains).
So in short, there's no easy way to do this without the help of some tools. That's ok with me, I can easily write a Perl script that parses a Sendmail style virtusertable and creates files to feed to Postfix.
But I am slightly disappointed. Doing what I want to do is easy in Sendmail - almost trivial. So far my experience is the opposite of what I have been reading everywhere - that Postfix is so much easier to configure than Sendmail.
Don't get me wrong, I don't want to go back to Sendmail but that's where I came from so it's going to take a while to switch my mindset to "the Postfix way".
Each piece of software has its own strengths and weaknesses. It simply isn't valid to compare one feature against another and assume that it holds true for all features across the board.
Postfix is easy enough to configure, but it does require reading some documentation to do so successfully. It is much more difficult when one tries to push Sendmail concepts into Postfix. And Sendmail will be trivial for you to configure because you are experienced with it. But it is not easy for others less experienced. Have you examined the size of the O'Reilly Sendmail book!
It would be VERY worth your while to a) get The Book of Postfix, and/or b) read and re-read the Postfix documentation starting here: http://www.postfix.org/documentation.html. There is a lot to learn.
Postfix's aim is to transfer and deliver mail and do so as securely as possible. Simplicity in configuration is also a factor. This doesn't mean it has built-in, programmatic recipient list generation. But there are plenty of features that Sendmail does not provide that Postfix does.
Constructing such a table takes just as much effort as, and is algorithmically similar to,
this postfix version using pcre:
Code:
/^john@mydomain\.com$/ User1
/^sales@mydomain\.com$/ User1
/^support@mydomain\.com$/ User2
if !/^list@mydomain\.com$/
if !/^news@mydomain\.com$/
if !/^spam@mydomain\.com$/
if !/junk@mydomain\.com$/
/.*@mydomain\.com$/ User3
endif
endif
endif
endif
Well, for now I've written a Perl script that takes a Sendmail-style virtusertable, and creates two other files (virt-user-table and recipient_access) that can be fed to Postfix.
The reason I'm not going for the pcre table is because other programs read the virtusertable too and they don't understand pcre style tables.
Perhaps others can use this script too, so I'm posting it here. Mind you, it took me about 30 minutes to write and test this so don't shoot me if you think it's coded inefficiently (although I doubt it is).
Code:
#!/usr/bin/perl
# This script splits a Sendmail style virtusertable into two files that can be used by Postix.
my $sendmail_vut = "/etc/postfix/virtusertable"; # Name of Sendmail style virtusertable used as input
my $postfix_vut = "/etc/postfix/virt-user-table"; # Name of Postfix style virtusertable used as output
my $postfix_rat = "/etc/postfix/recipient_access"; # Name of postfix style recipient access table used as output
my $includecommentsvut = "yes"; # If set to "yes" will include comments from the original file in the new virtusertable
my $includecommentsrat = "no"; # If set to "yes" will include comments from the original file in the new recipient_access file
my $rat_seperator = "#### Everyting Below this line was generated by makeconfig.pl. Do not change!!! ####";
my @orgratable = ();
if( open( RATABLE, "$postfix_rat" ) ) {
foreach $line (<RATABLE>) {
chomp( $line );
if( $line eq $rat_seperator ) {
last;
}
$orgratable[ $#orgratable + 1 ] = "$line\n";
}
close( RATABLE );
}
if( ! open( TABLE, "$sendmail_vut" ) ) {
error( "can't open $sendmail_vut for input.");
}
my @newvutable = (); # New virtusertable
my @newratable = (); # New recipient-access table
foreach $line (<TABLE>) {
chomp( $line );
$thisline = trim( $line );
if( $thisline ne "" && substr( $thisline, 0, 1 ) ne "#" ) {
# replace double spaces and double tabs for single space
$thisline =~ s/\s+/ /;
my ($email, $alias, @errormessage) = split( / /, $thisline );
if( lc( substr( $alias, 0, 6 ) ) eq "error:" ) {
# With sendmail, you can rewrite email adresses for a domain, *and* define a reject
# for the catchall like this:
#
# john@domain.com mb_john
# chris@domain.com mb_chris
# @domain.com error:nouser No such user here!
#
# Postfix does not support this. So comment the line, then put it in recipient_access
# Postfix rejects an unknown address anyway if no catchall is specified.
my $comment = substr( $email, 0, 1 ) eq "@" ? "# " : "";
my $error = (split( /:/, $alias ))[1];
if( lc( $error ) eq "nouser" ) {
$newratable[ $#newratable + 1 ] = "$comment$email\t\t550 @errormessage";
} else {
$newratable[ $#newratable + 1 ] = "$comment$email\t\t$error @errormessage";
}
} else {
$newvutable[ $#newvutable + 1 ] = $line;
}
} else {
$newvutable[ $#newvutable + 1 ] = $line if( lc($includecommentsvut) eq "yes" );
$newratable[ $#newratable + 1 ] = $line if( lc($includecommentsrat) eq "yes" );
}
}
close( TABLE );
if( ! open( OUTVUT, ">$postfix_vut" ) ) {
error( "can't open $postfix_vut for output." );
}
if( ! open( OUTRAT, ">$postfix_rat" ) ) {
close( OUTVUT );
error( "can't open $postfix_rat for output." );
}
print OUTVUT join( "\n", @newvutable );
print OUTRAT @orgratable;
print OUTRAT "$rat_seperator\n\n";
print OUTRAT join( "\n", @newratable );
close( OUTVUT );
close( OUTRAT );
print "Done.\n\n";
sub error {
my $message = shift;
print "Error: $message\n";
exit( -1 );
}
sub trim {
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.