https://wiki.preterhuman.net/index.php?title=Sendmail_Tutorial&feed=atom&action=historySendmail Tutorial - Revision history2024-03-29T06:47:49ZRevision history for this page on the wikiMediaWiki 1.35.0https://wiki.preterhuman.net/index.php?title=Sendmail_Tutorial&diff=17099&oldid=prevNetfreak at 23:28, 1 September 20202020-09-01T23:28:23Z<p></p>
<table class="diff diff-contentalign-left diff-editfont-monospace" data-mw="interface">
<col class="diff-marker" />
<col class="diff-content" />
<col class="diff-marker" />
<col class="diff-content" />
<tr class="diff-title" lang="en">
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">← Older revision</td>
<td colspan="2" style="background-color: #fff; color: #202122; text-align: center;">Revision as of 23:28, 1 September 2020</td>
</tr><tr><td colspan="2" class="diff-lineno" id="mw-diff-left-l365" >Line 365:</td>
<td colspan="2" class="diff-lineno">Line 365:</td></tr>
<tr><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"></td></tr>
<tr><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>[[Category:Internet]]</div></td><td class='diff-marker'> </td><td style="background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;"><div>[[Category:Internet]]</div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div><ins style="font-weight: bold; text-decoration: none;">[[Category:E-Mail]]</ins></div></td></tr>
</table>Netfreakhttps://wiki.preterhuman.net/index.php?title=Sendmail_Tutorial&diff=14181&oldid=prevNetfreak: Created page with "<pre> From: Eliot Lear <lear@NET.BIO.NET> The following was written by Dr. Charles Hedrick of Rutgers University sometime in 1985. Please read it with the understanding that..."2020-07-21T06:30:19Z<p>Created page with "<pre> From: Eliot Lear <lear@NET.BIO.NET> The following was written by Dr. Charles Hedrick of Rutgers University sometime in 1985. Please read it with the understanding that..."</p>
<p><b>New page</b></p><div><pre><br />
From: Eliot Lear <lear@NET.BIO.NET><br />
<br />
The following was written by Dr. Charles Hedrick of Rutgers University<br />
sometime in 1985. Please read it with the understanding that rule <br />
numbers are nothing more than function names. For further reference,<br />
I suggest the Sun Tutorial on Sendmail in their manuals.<br />
-eliot<br />
<br />
Command: followup<br />
Newsgroups: net.unix-wizards,net.mail<br />
To: steve@jplgodo.UUCP<br />
Subject: a brief tutorial on sendmail rules<br />
Distribution: <br />
References: <902@rlgvax.UUCP> <545@jplgodo.UUCP><br />
<br />
A previous message suggested using "sendmail -bt" to see how sendmail<br />
is going to process an address. This is indeed a handy command for<br />
testing how an address will be processed. However the instructions<br />
given were not quite right. To see how sendmail is going to deliver<br />
mail to a given address, a reasonable thing to type is<br />
sendmail -bt<br />
0,4 address<br />
Even this isn't quite right, but with "normal" rule sets it should work.<br />
<br />
Because there is so much confusion about sendmail rules, the rest of<br />
this message contains a brief tutorial. My own opinion of sendmail is<br />
that it is quite a good piece of work. Many people have complained<br />
about the difficulty of understanding sendmail rule sets. However I<br />
have also worked with mailers that code address processing directly<br />
into the program. I much prefer sendmail. The real problem is not<br />
with sendmail, but with the rules. The rules normally shipped from<br />
Berkeley have lots of code that does strange Berkeley-specific things,<br />
and they are not commented. Also, typical complex rule sets are<br />
trying to handle lots of things, forwarding mail among several<br />
different mail systems with incompatible addressing conventions. A<br />
rule set to handle just old-style (non-domain) UUCP mail would be very<br />
simple and easy to understand. But real rule sets are not doing<br />
simple things, so they are not simple.<br />
<br />
For those not familiar with sendmail, -bt invokes the rule tester. It<br />
lets you type a set of rule numbers and an address, and then shows you<br />
what the rules will do to that address. In addition, rule test mode<br />
automatically applies rule 3 before whatever rule you ask it to apply.<br />
As we will see shortly, this is a reasonable thing to do.<br />
<br />
Before describing the rule sets, let me define two terms: "header" and<br />
"envelope". Header refers to the lines at the beginning of the<br />
message, starting with "from:", "to:", "subject:", etc. Sendmail does<br />
process these lines. E.g. with uucp mail it will add its own host<br />
name at the beginning of the from line, so that the final recipient<br />
stands some change of replying to the message. However sendmail<br />
normally does not depend upon the from and to lines to perform its<br />
actual delivery. It has more direct knowledge, passed on to it from<br />
the program that generated the mail, or if it came from another site,<br />
the mailer at that site. This information is referred to as the<br />
"envelope", since it is like the addresses on the outside of an<br />
envelope. For Arpanet mail, the envelope is passed to the next site<br />
by the MAIL FROM: and RCPT TO: commands. For UUCP mail, it is passed<br />
on as arguments to the remote rmail command. To see why there have to<br />
be separate addresses "on the envelope", consider what happens when<br />
you send mail to "john@vax, mary@sun". Two copies of the message will<br />
be dispatched, one to vax and the other to sun. The "to: " line in<br />
the headers will show both addresses. However the envelope will show<br />
only the right address that we want this copy to go to. The copy sent<br />
to vax will show "john@vax" and the copy sent to sun will show<br />
"mary@sun". If sendmail had to look at the "to: " line, it would<br />
never know which of the addresses shown there it was responsible for<br />
handling.<br />
<br />
Anyway, here is what the rules do:<br />
<br />
3: always done first. This turns addresses from their normal textual<br />
form into a form that the rest of the rules understand. In most<br />
cases, all it does it put < > around the name of the host that is next<br />
in line. Thus foo@bar turns into foo<@bar>. However it also does a<br />
few transformations. E.g. it turns foo!bar!user into<br />
bar!user<@foo.UUCP>. Since sendmail accepts either ! syntax or<br />
@....UUCP syntax, rule 3 standardizes on @ syntax. It also does a few<br />
other minor things. But you won't be far off if you just think of it<br />
as adding < > around the host name.<br />
<br />
4: always done last. This turns addresses from internal form back<br />
into external form. It removes the < > around the host name, and<br />
turns foo@bar.UUCP back into bar!foo. Again, there are one or two<br />
other minor things, but you won't be too far off if you think of 4 as<br />
just removing the < > around the host name.<br />
<br />
0: This is the rule that handles the destination address on the<br />
envelope. It is in some sense the primary rule. It returns a triple:<br />
protocol, host, user. The protocol is usually one of local, TCP, or<br />
UUCP. At the moment, it figures this out syntactically. In our rule<br />
set, hosts ending in .UUCP are handled by UUCP, the current host is<br />
local, and everything else is TCP. As domains are integrated into<br />
UUCP, obviously this rule is going to change. This rule does very<br />
little other than simply look at the format of the host name, though<br />
as usual a few other details are involved (e.g. it removes the local<br />
host. So myhost!foo!bar will be sent directly to foo).<br />
<br />
1 and 2 are protocol-independent transformations used for sender and<br />
recipient lines in the header (i.e. from: and to: lines). In our<br />
rule sets, they don't do anything.<br />
<br />
Each protocol has its own rules to use for sender and recipient lines<br />
in the header. E.g. UUCP rules might add the local host name to the<br />
beginning of the from line and remove it from the to line. In our<br />
rule set, the complexities in these rules are primarily caused by<br />
forwarding between UUCP and TCP. The line that defines the mailer for<br />
a protocol lists the rule to use for source and recipient, in the S=<br />
and R=.<br />
<br />
Finally, here is the exact sequence in which these rules are used.<br />
For example, the first line means that the destination specified in<br />
the envelope is processed first by rule 3, then rule 0, then rule 4.<br />
<br />
envelope recipient: 3,0,4 [actually rule 4 is applied only to the<br />
user name portion of what rule 0 returns]<br />
envelope sender: 3,1,4<br />
header recipient: 3,2,xx,4 [xx is the rule number specified in R=]<br />
header sender: 3,1,xx,4 [xx is the rule number specified in S=]<br />
<br />
I have the impression that the sender from the envelope (the<br />
return-path) may actually get processed twice, once by 3,1,4 and the<br />
second time by 3,1,xx,4. However I'm not sure about that.<br />
<br />
Now for the format of the rules themselves. I'm just going to show<br />
some examples, since sendmail comes with a reference manual, which you<br />
can refer to. However these examples are probably enough to let you<br />
understand any set of rules that makes sense in the first place (which<br />
the normal rules do not). This example is from our UUCP definition.<br />
It a simplified version of the set of rules used to process the sender<br />
specification. As such, the major thing it has to do is to add our<br />
host name to the beginning, so that the guy at the end will know that<br />
the mail went through us.<br />
<br />
S13<br />
R$+<@$-.UUCP> $2!$1 u@host.UUCP => host!u<br />
R$=U!$+ $2 strip local name<br />
R$+ $:$U!$1 stick on our host name<br />
<br />
Briefly, the first rule turns the address from the form foo<@bar.UUCP><br />
back into bar!foo. The second rule removes our local host name, if<br />
it happens to be there already, so we don't get it twice. The third<br />
rule adds our host name to the beginning.<br />
<br />
S13 says that this is the beginning of a new rule set, number 13.<br />
<br />
R$+<@$-.UUCP> $2!$1 u@host.UUCP => host!u<br />
<br />
R says that this is a rule. The thing immediately after it,<br />
$+<@$-.UUCP> is a pattern. If this pattern matches the address, then<br />
the rule "triggers". If the rule triggers, the address is replaced<br />
with the "right hand side", i.e. what is after the tab(s). In this<br />
rule, the right hand sie is $2!$1. The thing after the next tab(s) is<br />
a comment. This rule is used in processing UUCP addresses. As noted<br />
above, by the time we get to it, rule 3 has already been applied. So<br />
if we had a UUCP address of the form host1!host2!user, it would now be<br />
in the form host2!user<@host1.UUCP>. This does match the pattern:<br />
<br />
$+ <@$- .UUCP> <br />
host2!user<@host1.UUCP><br />
<br />
$+ and $- are "wildcards" that match anything. $- will match exactly<br />
one word, while $+ will match any number. (By the way, with the<br />
increasing use of domains, this production should probably use<br />
$+.UUCP, not $-.UUCP.) Since the pattern matches, we replace this<br />
with the "right hand side" of the rule, $2!$1. $ followed by a digit<br />
means the Nth thing matched by a wildcard. In this case there were<br />
two wildcards, so<br />
$1 = host2!user<br />
$2 = host1<br />
The final result is <br />
host1!host2!user<br />
As you can see, we have simply turned UUCP addresses from the format<br />
produced by rule 3 back into normal ! format.<br />
<br />
The second rule is<br />
<br />
R$=U!$+ $2 strip local name<br />
<br />
This is needed because there are situations in which our host name<br />
ends up on the beginning of the recipient address. Since we are<br />
about to add our host name, we don't want it to be there twice.<br />
So if it was there before, we remove it. $= is used to see if<br />
something is a member of a specified "class". U happens to be a list<br />
of our UUCP host name and any nicknames. So $=U!$+ matches<br />
any address that begins with our host name or nickname, then !, then<br />
anything else. Suppose we had topaz!host1!host2!user. The<br />
match would be<br />
<br />
$=U !$+<br />
topaz!host1!host2!user<br />
<br />
The result of the match is that<br />
<br />
$1 = topaz<br />
$2 = host1!host2!user<br />
<br />
Since the right hand side of this rule is simply "$2", the result is<br />
<br />
host1!host2!user<br />
<br />
I.e. we have removed the topaz from the beginning. By the way, the<br />
class U used by the rule would have been defined earlier in the file<br />
by the statement<br />
<br />
CUtopaz ru-topaz<br />
<br />
C defines a class. U is the name of the class. The rest of the<br />
line is the list of things that will be in the class.<br />
<br />
Finally we have the rule<br />
<br />
R$+ $:$U!$1 stick on our host name<br />
<br />
The $+ matches anything. In this case the name is host1!host2!user, so the<br />
result of the match is<br />
<br />
$1 = host1!host2!user<br />
<br />
The result looks slightly obscure. $: is a tag that says to do this<br />
only once. The problem is that this rule always applies, since the<br />
pattern matches anything. Normally, rules are applied over and<br />
over, as long as they apply. In this case, the result would be<br />
an infinite loop. Putting $: at the beginning says to do it only<br />
once. $U says to use the value of the macro U. Earlier in the<br />
file we defined U as our UUCP host name, with a definition<br />
<br />
DUtopaz<br />
<br />
Note that there can be a class and a macro with the same name.<br />
$=U tests whether something is in the class U. $U is replaced<br />
by the value of the macro U.<br />
<br />
So the final value of this rule, $:$U!$1, is<br />
<br />
topaz!host1!host2!user<br />
<br />
So this rule has managed to add our host name to the beginning, as it<br />
was supposed to. Since there are no further rules in the set (the<br />
next line is the end of file or the beginning of a new rule set),<br />
this value is returned.<br />
<br />
There are several more magic things that can appear in a pattern.<br />
The most important are:<br />
<br />
$* - this is another wild card. It is similar to $+, but $+ matches<br />
anything, whereas $* matches both anything and nothing. I.e. $+<br />
matches 1 or more tokens and $* matches 0 or more tokens. So here<br />
is a list of the wildcards I have mentioned:<br />
<br />
$* 0 or more<br />
$+ 1 or more<br />
$- exactly 1<br />
$=x any member of class x<br />
<br />
A typical example of $* is a production where we aren't sure whether<br />
the user name is before or after the host name:<br />
<br />
R$*<@$+.UUCP>$* $@$1<@$2.UUCP>$3<br />
<br />
This production would test for the host name ending in .UUCP, and<br />
return immediately. $@ is a flag you haven't seen yet. It is simply<br />
a return statement. It causes the right hand side of this rule to be<br />
returned as the final value of this rule set.<br />
<br />
The other magic thing I will mention is $>. This is a subroutine<br />
call. Here is an example taken from rule set 24, which is used to<br />
process recipients in TCP mail. Its purpose is to handle the<br />
situation where we might have an address like topaz!user@red. (Our<br />
host name is topaz. Red is a local host that we talk to via TCP.)<br />
I.e. someone is asking us to relay mail to red. Rule 3 will have<br />
turned this into user@red<@topaz.UUCP>. What we want to do is<br />
get rid of the topaz.UUCP and treat red as the host. (Rule set 0<br />
would do this for the recipient on the envelope. This rule is<br />
used for the to: field in the header.) Here is the rule.<br />
<br />
R$+<@$=U.UUCP> $@$>9$1 in case local!a@b<br />
<br />
The pattern matches our example, as follows:<br />
<br />
$+ <@$=U .UUCP><br />
user@red<@topaz.UUCP><br />
<br />
Recall that $+ matches anything and $=U tests whether something is our<br />
UUCP host name or one of our nicknames. The result of the match is<br />
<br />
$1 = user@red<br />
$2 = topaz<br />
<br />
The right hand side is $@$>9$1. The $@ is the tag saying to stop the<br />
rule set here and return this value. $>9 is a subroutine call. It<br />
says to take the right hand side, pass it to rule set 9, and then<br />
use the value of rule set 9. The actual right hand side is simply<br />
$1, which in this case is user@red. Here is rule set 9:<br />
<br />
S9<br />
R$*<$*>$* $1$2$3 defocus<br />
R$+ $:$>3$1 make canonical<br />
R$+ $@$>24$1 and do 24 again<br />
<br />
The first rule simply removes < >. It is sort of a quick and dirty<br />
version of rule 4. In fact we have no < > left, since we have removed<br />
the <@topaz.UUCP>. So this rule does not trigger. (Now that I think<br />
about it, I suspect it is probably never going to trigger, and so is<br />
not needed.) <br />
<br />
The next rule is a simple subroutine call. It matches anything ($+<br />
matches any 1 or more token). The right hand side is $:$>3$1 The $:<br />
says to do it only once. Since the rule matches anything, you need<br />
this, or you will have an infinite loop. The $>3 says to call rule 3<br />
as a subroutine. The $1 is the actual right hand side. Since the<br />
left hand side matched the whole address, what this rule does is<br />
simply call rule set 3 on the whole address. Recall that rule set 3<br />
basically locates the host name and puts < > around it. So in this<br />
case the result is user<@red>. As you can see, it was not enough to<br />
remove <@topaz.UUCP>. That leaves us with no host name. We have to<br />
call rule 3 to find the current host name and put < > around it.<br />
<br />
The last rule is really just a goto statement. The pattern is $+,<br />
which matches anything, so it always triggers. The right hand side is<br />
$@$>24$1. The $@ is the return tag. It says to stop this rule set<br />
and return that value. $>24 says to call rule set 24. The actual<br />
right hand side is $1, so we call rule set 24 with the whole address.<br />
If you recall, this ruleset (9) was called from the middle of 24 when<br />
we found user@red<@topaz.UUCP>. So what we have done is to change<br />
this into user<@red> and say to start rule set 24 over again.<br />
<br />
I hope you have found this exposition useful. As a final convenience,<br />
here is a "reference card" for reading rule sets. Note that this<br />
contains only operators used by the rules. There are plenty of<br />
other facilities used in the configuration section which I am<br />
not documenting here. (I'd love to see someone produce a complete<br />
reference card.)<br />
<br />
wildcards:<br />
$* 0 or more tokens<br />
$+ 1 or more tokens<br />
$- exactly one token<br />
$=x member of class x (x must be a letter, lower/upper case distinct)<br />
$~x not a member of class x<br />
<br />
macro values (usable in pattern or on right hand side)<br />
$x value of macro x (x must be a letter, lower/upper case distinct)<br />
At least on the Pyramid, $x is replaced by the macro's value<br />
when the sendmail.cf file is being read in.<br />
<br />
on the right hand side:<br />
$n string matched by the Nth wildcard<br />
$>n call rule set N as a subroutine<br />
$@ return<br />
$: only do this rule once<br />
<br />
in rule 0, defining the return value<br />
$# protocol<br />
$@ host<br />
$: user<br />
<br />
Rutgers extensions, usable only on right hand side<br />
$%n take the string matched by the Nth wildcard, look it up in<br />
/etc/hosts, and if found use the primary host name<br />
$&x use the current value of macro x. x must be a letter.<br />
upper and lower case are treated as distinct.<br />
</pre><br />
<br />
[[Category:Internet]]</div>Netfreak