I just saw a message on the postfix list where someone criticised the postfix-admin vacation message functionlaity because:
"... it does not use the envelope sender nor the envelope recipient..."
First, is this true? If so, this is not good...I wish I could tell from reading the code, but I'm not a programmer...
Also, while I'm on this topic, there's something I've always wanted to understand better.
Is there a detailed list of the processing that occurs to prevent vacation messages from being sent when they shouldn't be sent? Like, for example, in a thread on the postfix list last year, the following was discussed and these specifics were spelled out as to what constituted 'good' vacation message behavior, and I'm very interested to learn how well the postfix-admin vacation message functionality adheres to these rules. I apologize for the length below, but I think this deserves careful consideration:
Begin thread copy/paste:
Original poster:
>> I know that most people on this list hate vacation/auto-responder type
>> messages, but I also know that the same people care even more about them
>> working properly when they are used.
>>
>> With that in mind, I'd like comments (criticism, suggestions to make it
>> better behaved) on the one that works with dovecot. From the wiki:
>> (http://tinyurl.com/2lxwr8):
>>
>> ****************************************
>>
>> Vacation auto-reply
>>
>> The vacation replies are sent to the envelope sender. Currently this is
>> taken from the Return-Path: header in the message.
mouss replied:
> or from the command line if this is supported.
>
> if the envelope sender is not available, no reply should be sent.
>> The automatic replies shouldn't be sent if any of the following
>> are true:
>>
>> * Auto-Submitted: header exists with any value except "no"
>> * Precedence: header exists with value "junk", "bulk" or "list"
>> * The envelope sender
>> o begins with "MAILER-DAEMON" (case-insensitive)
>> o begins with "LISTSERV" (case-insensitive)
>> o begins with "majordomo" (case-insensitive)
>> o begins with "owner-" (case-sensitive)
mouss replied:
> replace with:
> starts with "${token}-" (not case sensitive), where token is
> one of: owner, request, bounces
>
> It is safer to send nothing than send a risky one.
>> o contains the string "-request" anywhere within it (case-
>> sensitive)
mouss replied:
> replace with
> o contains "-${token}@" (not case sensitive), where token
> is one of: owner, request, bounces
>> * The envelope sender and envelope recipient are the same
>> * The envelope recipient is not found in the message To:, Cc: or
>> Bcc: fields.
mouss replied:
> * There is a "Sender:" header containing one of the tokens listed
> above.
> * There is a List-Id or List-Post header
> * There is no header suggesting that this is possible spam
>
> Unlike delivery, safety here is to not send a reply if the message
> may be spam. so you don't rely on recipient preferences, and you
> don't fear flase positives too much (the guy who receives your
> auto-reply may have a better filter, and besides annoying him, would
> find you stupid to miss an obvious spam ;-p)
>> The envelope sender is taken from a Return-Path: header in the
>> message. The envelope recipient is taken from the recipient user
>> (-d parameter with virtual user setup). A bare username without a
>> domain gets canonicalised by the libsieve code to
> "<username>@unspecified-domain", which means it is highly unlikely to
> pass the last two tests in the list above.
mouss replied:
> the enveleope recipient can also be retrieved in the Delivered-To
> header if this is available ('D' flag).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm very surprised... is NO ONE ELSE concerned about the inner workings of this script?
Is no one else concerned about whether or not it responds when it should, but moreimportantly DOES NOT respond when it SHOULDN'T?
As I said in the initial post, I'm not a programmer, and am unable to tell from simply reading the vacation script, what measures it takes to not respond when it shouldn't.
I'm most concerned about the claim that it doesn't reply to the envelope FROM, but instead replies to the From HEADER, which is easily forged.
Please... would someone who knows and understands this script, please respond to the specific details outlined above?
Thanks,
Charles
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi, I mean to reply to this; but I've been a bit busy to...
Yes, it does appear to rely on the headers in the email to handle to/from; I'm not sure why this is - it certainly _seems_ the wrong behaviour.
Presumably the correct behaviour is to ignore the to/from in any headers, and use the SMTP RCPT TO / FROM fields, which should be passed into the script via $argv?
David.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
No worries... its quite a detailed question/issue, so I appreciate that it would take some time to properly address...
Yes, you are right, it most definitely should use the SMTP MAIL FROM and RCPT TO commands, not the headers.
I'd also like to see if any of the other checks that were suggested that are not already used could be added (while we're looking at it)...
Lets make the postfixadmin vacation message something to be used as a reference for those people who like to call vacation auto responders 'evil' - I'd like them to be able to say 'but if you *must* use one, *please* use a sane one like the one used by postfixadmin!'...
:)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'd really like to get this aspect of Postfixadmin improved so that the vacation behavior conforms to the 'Best practices' for an auto-responder.
Please, anyone who knows how to read this code (and maybe even improve it), can you take some time to analyse my initial message and then the vacation script?
Thanks,
Charles
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
With all of the talk of modularizing postfixadmin, which will require a total rewrite of much of the code, I'd like to again make a call to first, BEFORE doing that kind of thing, please, please, please lets get the Vacation functionality fixed up...
I think it (the ability to easily enable/disable a 'vacation' message) is an extremely important aspect of postfixadmin - in fact, it is one of the main reasons I decided to use it myself - but there are people on the postfix mail list that denigrate postfixadmin solely because of the vacation script functionality 'bugs' - meaning, failure to behave the way a proper vacation script should.
... if I was a coder and could do this myself, I wouldn't hesitate ...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I try to do the tests on the email address, stripping all other components from the address fields. It seems right for me, but I can accept other ideas.
For now, I did not get rid of the previous tests made on header recipient/sender addresses: I agree with mouss that when in doubt it's better to send nothing.
In master.cf it has to be called this way:
vacation unix - n n - - pipe
flags=Rq user=vacation argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${recipient}
The patch is against the version found in PA-2.2.1.1 and contains the 2 patches I submitted 2-3 days ago too (interval notification and CentOS5 DBI compatibility).
I would like to hear feedback. Be warned that it was only very basically tested on my home server for now.
Luigi
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Would it be possible for you to list, precisely, but in plain english, what each step of the code does?
Example:
1. tests for vacatation enabled
2. if enabled, tests interval against sender/interval db
3. performs following checks:
a) tests for NULL <> sender
etc... you get the idea...
I'd really like to understand exactly how it works. Also, once this is officially integrated, I this it should be well documented on, or just off of the home page, complete with a request for additional checks that could be added to make its behavior even safer...
But regardless... thanks so much to Luigi and GingerDog for making this happen! I'm very excited about upgrading once it is official...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hmmm, again the Perpetual Documentation Problem. The code here is particularly self-explaining. Below I'll try to tell what is done in reference to the code chunks. But honestly I think you should try to read the code. It's not that hard, me too am not a pro coder. I think that documentation about this topic would quickly become obsolete when changes are made to the script.
So on to the code (comments are after the # sign):
while (<STDIN>) { # reading the message from standard input
...
# if we find the x-spam-flag: or x-spam-status: flag, exit doing nothing; the comparison is not case-sensitive (the /i )
elsif (/^x-spam-(flag|status):\s+yes/i) { exit (0); }
# if we find the precedence: header followed by space (\s+) and one of the bulk, list, junk words, exit doing nothing;
elsif (/^precedence:\s+(bulk|list|junk)/i) { exit (0); }
# if we find the x-loop: header followed by space (\s+) and the string "postfix admin virtual vacation", exit doing nothing. Hey: we check a x-loop header that we never insert: this will be the object of another patch
elsif (/^x-loop:\s+postfix\ admin\ virtual\ vacation/i) { exit (0); }
# if we find Auto-Submitted: no , let's go on
elsif (/^Auto-Submitted:\s+no/i) { next; }
# if we find Auto-Submitted: with anything else, exit doing nothing;
elsif (/^Auto-Submitted:/i) { exit (0); }
# if we find List-Id: or List-Post header, exit doing nothing
elsif (/^List-(Id|Post):/i) { exit (0); }
...
# if any of the to, from, messageid header fields, or envelope sender/recipient are not set, then exit. Maybe it can be discussed if, now that we use evelope sender and recipient, it does make sense checking the header from/to. I think the answer is still yes.
if (!$from || !$to || !$messageid || !$sender || !$recipient) { exit (0); }
# If the envelope sender begins (the ^) with mailer-daemon or listserv or majordomo or owner- or request- or bounces- , exit doing nothing
if ( $sender =~ /^(mailer-daemon|listserv|majordomo|owner-|request-|bounces-)/i) { exit (0); }
# If the envelope sender contains (note the absence of ^) -owner@ or -request@ or -bounces@ , exit doing nothing
if ( $sender =~ /-(owner|request|bounces)\@/i) { exit (0); }
# the strip_address sub strips anything but the mail address so in $ss we have the mail address of the envelope sender
my $ss = strip_address($sender);
my $sr = strip_address($recipient);
my $ssh = strip_address($sndrhdr);
# if the mail address of the evelope sender is the same of the recipient's, then exit
if ($ss eq $sr) { exit(0); }
# here we loop over a list made of the recipients found in the to, cc, and bcc header fields
for (split(/,\s*/, lc($to)), split(/,\s*/, lc($cc)), split(/,\s*/, lc($bcc))) {
my $destinatario = strip_address($_); # we take only the address of the recipient we're looping on
if ($ssh eq $destinatario) { exit(0); } # if it's equal to the Sender: header mail address, then exit. Hey! Shouldn't we check $sh too for this?
if ($sr eq $destinatario) { $recipfound++; } # increment a variable (initially 0) if we found that it was equale to the envelope recipient mail address
}
if (!$recipfound) { exit (0); } # if we did not find any to, cc, or bcc header field values matchng the envelope recipient, then exit
# use a standard module to check if the from header field has a valid dns entry
if (!Email::Valid->address($from,-mxcheck => 1)) { exit(0); }
# the same for the envelope sender mail address
if (!Email::Valid->address($ss,-mxcheck => 1)) { exit(0); }
# some of the checks performed on the from header value
if ($from eq "" || $from =~ /^(owner-|-(?:request|owner)\@|^(?:mailer-daemon|postmaster)\@)/i) { exit (0); }
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Correction to my prevous post: the x-loop header is inserted. I missed it.
For the other thing, I think we should add the line
if ($ss eq $destinatario) { do_debug("envelope sender $ss contains recipient $destinatario"); exit(0); }
over or under the one with
if ($ssh eq $destinatario) { do_debug("sender header $sender contains recipient $destinatario"); exit(0); }
to theck again if the sender envelope address is contained in the header recipients. Maybe redundant, but "melius est abundare".
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This is awesome... very comprehensive, and looks like it contains all of the checks mouss recommended... and I agree with you that we should *also* check the header from/recipients - can't hurt, but I guess the only question (that I cannot answer) is, does it really accomplish anything? Meaning, will it catch anything that the envelope sender/recipient checks won't?
Do you mind if I invite him to this thread for comments/suggestions?
Thank you very, very much for taking the time to do this!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
> does it really accomplish anything?
> Meaning, will it catch anything that the
> envelope sender/recipient checks won't?
At a first glance, I think the answer is no. BUT it's highly likely I'm missing some particular cases. I just wrote in Perl, as good as I can, what mouss told to do. I think that leaving the checks on the from/to headers or removing them should be the object of some discussion. In the meanwhile, leaving them there will not hurt (I think).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Understood... and again, your efforts are very much appreciated.
I have invited mouss to come and participate, since he has expressed interest in 'properly functioning vacation messages', so hopefully he will be commenting directly sometime soon...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Just a quick note - I've merged Lux's patch and am currently rewriting the logging done by the script to use log4perl (this should make it easier for people to understand what it's doing).
I'm almost ready to commit it, but am hoping to write a simple 'test' harness or something to help show that it is (or isn't!) working.
David.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I tested this new vacation.pl and found a problem. Because my usernames include the domain, the envelope address vacation.pl sees is (sample) bob#example.com@autoreply.example.com
It seems that strip_address() "fixes" this to example.com@autoreply.example.com, which is not found in the envelope recipient list, thus:
2008/08/06 15:56:10 DEBUG> /var/spool/vacation/vacation.pl:475 main:: - smtp envelope recipient example.com@autoreply.example.com not found in the header recipients (therefore they were bcc'ed, so won't send vacation message)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Here I see two distinct issues.
If I put the line
$logger->debug("Examining message $messageid - smtp sender $smtp_sender - smtp recipient $smtp_recipient");
just after the assignment
$smtp_recipient = shift || $smtp_recipient || $ENV{"USER"} || "";
I find in the log a line saying
Examining message <20080807061344....@...> - smtp sender <lux@ten.biz> - smtp recipient "lux@domain.com"@autoreply.domain.com
In my case, strip_address strips exactly lux@domain.com , just because there are the '"' and because the "@domain.com" comes before the "@autoreply.domain.com". I use flags=Rq (see the q) in master.cf
In your case, I think the regexp the result is not what you expected to see because it seems you have a # in the place of the @ in the user name. I don't know why, this depends upon your setup.
Maybe, we should accept other characters in the local email address part in strip domain (seems that ! # $ * / ? | ^ { } ` ~ & ' + = are legal). But this alone won't solve your issue.
Maybe we should strip the @autoreply.domain.com part before trying to isolate the recipient email address, just to be sure not to take this into account when we lookfor the recipient address.
Maybe you could use ${user} instead of ${recipient} in master.cf. This should expand to bob#example.com . Still remains the # issue.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
As detailed in my previous post, I think that in the setup instructions we should recomment to use the command line
argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${user}
instead of
argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${recipient}
in a purely virtual mailbox setup (as is with vanilla PostfixAdmin).
And we should add the ! # $ * / ? | ^ { } ` ~ & ' + = characters in the local part of the email address stripped in strip_address.
Looking at the RFC, we should accept quoted local parts too. Maybe there is a perl module to handle this correctly.
Comments before patching?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Seems to be okay, I get the right debug messages. Other than the "#" vs "@" issue. I thought I recalled this coming up somewhere in the postfix docs, but can't find anything yet.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I just saw a message on the postfix list where someone criticised the postfix-admin vacation message functionlaity because:
"... it does not use the envelope sender nor the envelope recipient..."
First, is this true? If so, this is not good...I wish I could tell from reading the code, but I'm not a programmer...
Also, while I'm on this topic, there's something I've always wanted to understand better.
Is there a detailed list of the processing that occurs to prevent vacation messages from being sent when they shouldn't be sent? Like, for example, in a thread on the postfix list last year, the following was discussed and these specifics were spelled out as to what constituted 'good' vacation message behavior, and I'm very interested to learn how well the postfix-admin vacation message functionality adheres to these rules. I apologize for the length below, but I think this deserves careful consideration:
Begin thread copy/paste:
Original poster:
>> I know that most people on this list hate vacation/auto-responder type
>> messages, but I also know that the same people care even more about them
>> working properly when they are used.
>>
>> With that in mind, I'd like comments (criticism, suggestions to make it
>> better behaved) on the one that works with dovecot. From the wiki:
>> (http://tinyurl.com/2lxwr8):
>>
>> ****************************************
>>
>> Vacation auto-reply
>>
>> The vacation replies are sent to the envelope sender. Currently this is
>> taken from the Return-Path: header in the message.
mouss replied:
> or from the command line if this is supported.
>
> if the envelope sender is not available, no reply should be sent.
>> The automatic replies shouldn't be sent if any of the following
>> are true:
>>
>> * Auto-Submitted: header exists with any value except "no"
>> * Precedence: header exists with value "junk", "bulk" or "list"
>> * The envelope sender
>> o begins with "MAILER-DAEMON" (case-insensitive)
>> o begins with "LISTSERV" (case-insensitive)
>> o begins with "majordomo" (case-insensitive)
>> o begins with "owner-" (case-sensitive)
mouss replied:
> replace with:
> starts with "${token}-" (not case sensitive), where token is
> one of: owner, request, bounces
>
> It is safer to send nothing than send a risky one.
>> o contains the string "-request" anywhere within it (case-
>> sensitive)
mouss replied:
> replace with
> o contains "-${token}@" (not case sensitive), where token
> is one of: owner, request, bounces
>> * The envelope sender and envelope recipient are the same
>> * The envelope recipient is not found in the message To:, Cc: or
>> Bcc: fields.
mouss replied:
> * There is a "Sender:" header containing one of the tokens listed
> above.
> * There is a List-Id or List-Post header
> * There is no header suggesting that this is possible spam
>
> Unlike delivery, safety here is to not send a reply if the message
> may be spam. so you don't rely on recipient preferences, and you
> don't fear flase positives too much (the guy who receives your
> auto-reply may have a better filter, and besides annoying him, would
> find you stupid to miss an obvious spam ;-p)
>> The envelope sender is taken from a Return-Path: header in the
>> message. The envelope recipient is taken from the recipient user
>> (-d parameter with virtual user setup). A bare username without a
>> domain gets canonicalised by the libsieve code to
> "<username>@unspecified-domain", which means it is highly unlikely to
> pass the last two tests in the list above.
mouss replied:
> the enveleope recipient can also be retrieved in the Delivered-To
> header if this is available ('D' flag).
I'm very surprised... is NO ONE ELSE concerned about the inner workings of this script?
Is no one else concerned about whether or not it responds when it should, but moreimportantly DOES NOT respond when it SHOULDN'T?
As I said in the initial post, I'm not a programmer, and am unable to tell from simply reading the vacation script, what measures it takes to not respond when it shouldn't.
I'm most concerned about the claim that it doesn't reply to the envelope FROM, but instead replies to the From HEADER, which is easily forged.
Please... would someone who knows and understands this script, please respond to the specific details outlined above?
Thanks,
Charles
Hi, I mean to reply to this; but I've been a bit busy to...
Yes, it does appear to rely on the headers in the email to handle to/from; I'm not sure why this is - it certainly _seems_ the wrong behaviour.
Presumably the correct behaviour is to ignore the to/from in any headers, and use the SMTP RCPT TO / FROM fields, which should be passed into the script via $argv?
David.
Hi David,
No worries... its quite a detailed question/issue, so I appreciate that it would take some time to properly address...
Yes, you are right, it most definitely should use the SMTP MAIL FROM and RCPT TO commands, not the headers.
I'd also like to see if any of the other checks that were suggested that are not already used could be added (while we're looking at it)...
Lets make the postfixadmin vacation message something to be used as a reference for those people who like to call vacation auto responders 'evil' - I'd like them to be able to say 'but if you *must* use one, *please* use a sane one like the one used by postfixadmin!'...
:)
Just being the squeaky wheel...
I'd really like to get this aspect of Postfixadmin improved so that the vacation behavior conforms to the 'Best practices' for an auto-responder.
Please, anyone who knows how to read this code (and maybe even improve it), can you take some time to analyse my initial message and then the vacation script?
Thanks,
Charles
Thanks for the reminder; I'm keen to improve it - although finding time to seems difficult :-( (I'll try and release postfixadmin 2.2.1 first)
Oh, no worries... I'm just playing the part of the 'squeaky wheel'... :)
Thanks!
With all of the talk of modularizing postfixadmin, which will require a total rewrite of much of the code, I'd like to again make a call to first, BEFORE doing that kind of thing, please, please, please lets get the Vacation functionality fixed up...
I think it (the ability to easily enable/disable a 'vacation' message) is an extremely important aspect of postfixadmin - in fact, it is one of the main reasons I decided to use it myself - but there are people on the postfix mail list that denigrate postfixadmin solely because of the vacation script functionality 'bugs' - meaning, failure to behave the way a proper vacation script should.
... if I was a coder and could do this myself, I wouldn't hesitate ...
I wrote a (0.0 release, alpha, test) patch to support mouss suggestions. You can find it for some days on http://www.iotti.biz/vacation/vacation.pl.useEnvelope.diff
I try to do the tests on the email address, stripping all other components from the address fields. It seems right for me, but I can accept other ideas.
For now, I did not get rid of the previous tests made on header recipient/sender addresses: I agree with mouss that when in doubt it's better to send nothing.
In master.cf it has to be called this way:
vacation unix - n n - - pipe
flags=Rq user=vacation argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${recipient}
The patch is against the version found in PA-2.2.1.1 and contains the 2 patches I submitted 2-3 days ago too (interval notification and CentOS5 DBI compatibility).
I would like to hear feedback. Be warned that it was only very basically tested on my home server for now.
Luigi
Hi Luigi,
Nice patch - you've saved me from doing it this weekend!
I'll try and test it - the patch itself looks fine from a first run through, so thank you!
David.
Yay! Luigi is my here of the day!
Seriously, thanks, this is great...
Would it be possible for you to list, precisely, but in plain english, what each step of the code does?
Example:
1. tests for vacatation enabled
2. if enabled, tests interval against sender/interval db
3. performs following checks:
a) tests for NULL <> sender
etc... you get the idea...
I'd really like to understand exactly how it works. Also, once this is officially integrated, I this it should be well documented on, or just off of the home page, complete with a request for additional checks that could be added to make its behavior even safer...
But regardless... thanks so much to Luigi and GingerDog for making this happen! I'm very excited about upgrading once it is official...
Hmmm, again the Perpetual Documentation Problem. The code here is particularly self-explaining. Below I'll try to tell what is done in reference to the code chunks. But honestly I think you should try to read the code. It's not that hard, me too am not a pro coder. I think that documentation about this topic would quickly become obsolete when changes are made to the script.
So on to the code (comments are after the # sign):
while (<STDIN>) { # reading the message from standard input
...
# if we find the x-spam-flag: or x-spam-status: flag, exit doing nothing; the comparison is not case-sensitive (the /i )
elsif (/^x-spam-(flag|status):\s+yes/i) { exit (0); }
# if we find the precedence: header followed by space (\s+) and one of the bulk, list, junk words, exit doing nothing;
elsif (/^precedence:\s+(bulk|list|junk)/i) { exit (0); }
# if we find the x-loop: header followed by space (\s+) and the string "postfix admin virtual vacation", exit doing nothing. Hey: we check a x-loop header that we never insert: this will be the object of another patch
elsif (/^x-loop:\s+postfix\ admin\ virtual\ vacation/i) { exit (0); }
# if we find Auto-Submitted: no , let's go on
elsif (/^Auto-Submitted:\s+no/i) { next; }
# if we find Auto-Submitted: with anything else, exit doing nothing;
elsif (/^Auto-Submitted:/i) { exit (0); }
# if we find List-Id: or List-Post header, exit doing nothing
elsif (/^List-(Id|Post):/i) { exit (0); }
...
# if any of the to, from, messageid header fields, or envelope sender/recipient are not set, then exit. Maybe it can be discussed if, now that we use evelope sender and recipient, it does make sense checking the header from/to. I think the answer is still yes.
if (!$from || !$to || !$messageid || !$sender || !$recipient) { exit (0); }
# If the envelope sender begins (the ^) with mailer-daemon or listserv or majordomo or owner- or request- or bounces- , exit doing nothing
if ( $sender =~ /^(mailer-daemon|listserv|majordomo|owner-|request-|bounces-)/i) { exit (0); }
# If the envelope sender contains (note the absence of ^) -owner@ or -request@ or -bounces@ , exit doing nothing
if ( $sender =~ /-(owner|request|bounces)\@/i) { exit (0); }
# the strip_address sub strips anything but the mail address so in $ss we have the mail address of the envelope sender
my $ss = strip_address($sender);
my $sr = strip_address($recipient);
my $ssh = strip_address($sndrhdr);
# if the mail address of the evelope sender is the same of the recipient's, then exit
if ($ss eq $sr) { exit(0); }
# here we loop over a list made of the recipients found in the to, cc, and bcc header fields
for (split(/,\s*/, lc($to)), split(/,\s*/, lc($cc)), split(/,\s*/, lc($bcc))) {
my $destinatario = strip_address($_); # we take only the address of the recipient we're looping on
if ($ssh eq $destinatario) { exit(0); } # if it's equal to the Sender: header mail address, then exit. Hey! Shouldn't we check $sh too for this?
if ($sr eq $destinatario) { $recipfound++; } # increment a variable (initially 0) if we found that it was equale to the envelope recipient mail address
}
if (!$recipfound) { exit (0); } # if we did not find any to, cc, or bcc header field values matchng the envelope recipient, then exit
# use a standard module to check if the from header field has a valid dns entry
if (!Email::Valid->address($from,-mxcheck => 1)) { exit(0); }
# the same for the envelope sender mail address
if (!Email::Valid->address($ss,-mxcheck => 1)) { exit(0); }
# some of the checks performed on the from header value
if ($from eq "" || $from =~ /^(owner-|-(?:request|owner)\@|^(?:mailer-daemon|postmaster)\@)/i) { exit (0); }
Correction to my prevous post: the x-loop header is inserted. I missed it.
For the other thing, I think we should add the line
if ($ss eq $destinatario) { do_debug("envelope sender $ss contains recipient $destinatario"); exit(0); }
over or under the one with
if ($ssh eq $destinatario) { do_debug("sender header $sender contains recipient $destinatario"); exit(0); }
to theck again if the sender envelope address is contained in the header recipients. Maybe redundant, but "melius est abundare".
Hi,
Patch merged - I'm working on changing the logging used to use log4perl, which should improve things too.
(*Note: I've not tested the patch, but it's in trunk, which should be warning enough*)
David.
Wow!
This is awesome... very comprehensive, and looks like it contains all of the checks mouss recommended... and I agree with you that we should *also* check the header from/recipients - can't hurt, but I guess the only question (that I cannot answer) is, does it really accomplish anything? Meaning, will it catch anything that the envelope sender/recipient checks won't?
Do you mind if I invite him to this thread for comments/suggestions?
Thank you very, very much for taking the time to do this!
Anyone is welcome to comment/raise tickets/test/submit patches for the codebase; I'm not fussy! If it's an improvement it'll get in :)
> does it really accomplish anything?
> Meaning, will it catch anything that the
> envelope sender/recipient checks won't?
At a first glance, I think the answer is no. BUT it's highly likely I'm missing some particular cases. I just wrote in Perl, as good as I can, what mouss told to do. I think that leaving the checks on the from/to headers or removing them should be the object of some discussion. In the meanwhile, leaving them there will not hurt (I think).
Understood... and again, your efforts are very much appreciated.
I have invited mouss to come and participate, since he has expressed interest in 'properly functioning vacation messages', so hopefully he will be commenting directly sometime soon...
Hi,
Just a quick note - I've merged Lux's patch and am currently rewriting the logging done by the script to use log4perl (this should make it easier for people to understand what it's doing).
I'm almost ready to commit it, but am hoping to write a simple 'test' harness or something to help show that it is (or isn't!) working.
David.
vacation.pl updated with better logging etc and crude tests....
I tested this new vacation.pl and found a problem. Because my usernames include the domain, the envelope address vacation.pl sees is (sample) bob#example.com@autoreply.example.com
It seems that strip_address() "fixes" this to example.com@autoreply.example.com, which is not found in the envelope recipient list, thus:
2008/08/06 15:56:10 DEBUG> /var/spool/vacation/vacation.pl:475 main:: - smtp envelope recipient example.com@autoreply.example.com not found in the header recipients (therefore they were bcc'ed, so won't send vacation message)
Here I see two distinct issues.
If I put the line
$logger->debug("Examining message $messageid - smtp sender $smtp_sender - smtp recipient $smtp_recipient");
just after the assignment
$smtp_recipient = shift || $smtp_recipient || $ENV{"USER"} || "";
I find in the log a line saying
Examining message <20080807061344....@...> - smtp sender <lux@ten.biz> - smtp recipient "lux@domain.com"@autoreply.domain.com
In my case, strip_address strips exactly lux@domain.com , just because there are the '"' and because the "@domain.com" comes before the "@autoreply.domain.com". I use flags=Rq (see the q) in master.cf
In your case, I think the regexp the result is not what you expected to see because it seems you have a # in the place of the @ in the user name. I don't know why, this depends upon your setup.
Maybe, we should accept other characters in the local email address part in strip domain (seems that ! # $ * / ? | ^ { } ` ~ & ' + = are legal). But this alone won't solve your issue.
Maybe we should strip the @autoreply.domain.com part before trying to isolate the recipient email address, just to be sure not to take this into account when we lookfor the recipient address.
Maybe you could use ${user} instead of ${recipient} in master.cf. This should expand to bob#example.com . Still remains the # issue.
As detailed in my previous post, I think that in the setup instructions we should recomment to use the command line
argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${user}
instead of
argv=/var/spool/vacation/vacation.pl -f ${sender} -- ${recipient}
in a purely virtual mailbox setup (as is with vanilla PostfixAdmin).
And we should add the ! # $ * / ? | ^ { } ` ~ & ' + = characters in the local part of the email address stripped in strip_address.
Looking at the RFC, we should accept quoted local parts too. Maybe there is a perl module to handle this correctly.
Comments before patching?
Seems to be okay, I get the right debug messages. Other than the "#" vs "@" issue. I thought I recalled this coming up somewhere in the postfix docs, but can't find anything yet.
Ah, the "#" replacement is done in postfixadmin; specifically edit-vacation.php:
$vacation_domain = $CONF['vacation_domain'];
$vacation_goto = preg_replace('/@/', '#', $fUsername);
$vacation_goto = $vacation_goto . '@' . $vacation_domain;
I can't see where this was handled going the other way in vacation.pl in the released version. I guess I'm just looking on the surface...