On 2008-06-20 at 00:07 -0400, Eli C wrote:
> Do you have an example of this?
I have a rather complex setup for my laptop. It does this and more.
Details below. Used on MacOS.
> And thanks for the tip about checking for TLS if using auth PLAIN. Does
> $tls_cipher count SSL connections as well? A disturbing number of
> servers use PLAIN over unencrypted SMTP...
AFAIK, $tls_cipher counts SSL connections, but I don't think Exim
supports SSL-on-connect outbound. That is strictly for legacy client
support, Exim supports it for inbound connections only. I think.
Okay, my laptop. This does not highlight how easy Exim can be to
configure for many scenarios (once you know _how_, which is always the
sticking point); rather, it's a glimpse of the power you get from the
rather complete string expansion language. And a glimpse of how nuts I
am.
There will be various macros and hostlists which you define for
yourself. There are two special external files which are the heart of
it. "smarthosts" and "client-passwords". Example here uses Gmail
because that's what I have configured (various disclaimers apply).
Gmail's delivery folks aren't entirely enthralled with people routing
mail through Gmail and sending bounces, risking mail-loops, etc, so if
you mismanage this and damage your account's spam reputation score, on
your head be it.
smarthosts:
----------------------------8< cut here >8------------------------------
gmail.com: host=smtp.gmail.com submission=yes tls=yes user=nobody@???
googlemail.com: host=smtp.gmail.com submission=yes tls=yes user=nobody@???
*: host=mail.example.org submission=yes tls=yes
----------------------------8< cut here >8------------------------------
For the "client-passwords" file, I don't keep that in source-code
control and I'm not on the laptop right now, so I might be making a
mistake, but I believe it goes something like:
----------------------------8< cut here >8------------------------------
nobody@???: password=12345678
mail.example.org: user=fred password=sekret
----------------------------8< cut here >8------------------------------
Note how when a user is specified in smarthosts, the client-passwords
file is keyed by that, otherwise it's keyed by the smarthost (or parent
domains thereof).
Routers first; the first Router lets me declare for which domains I'll
send direct to MX, by creating a file named for the domain in a special
directory. The second Router verifies DNS so that I don't pass invalid
domains on and damage my reputation with remote systems; this does mean
that I need to be online whilst submitting email to Exim though.
----------------------------8< cut here >8------------------------------
begin routers
direct_to_mx:
driver = dnslookup
domains = partial()dsearch;DIRECT_OUT_DIR
transport = remote_smtp
ignore_target_hosts = +special_ipv4_bad
same_domain_copy_routing
no_more
remote_dns_verify:
driver = dnslookup
domains = ! +local_domains
transport = remote_smtp
ignore_target_hosts = +special_ipv4_bad
same_domain_copy_routing
verify_only
no_more
smarthost:
driver = manualroute
domains = ! +local_domains
transport = smarthost_smtp
ignore_target_hosts = +special_ipv4_bad
route_data = ${extract{host}{${lookup{$domain}partial()lsearch*{RUNCONFDIR/smarthosts}}}}
address_data = ${lookup{$domain}partial()lsearch*{RUNCONFDIR/smarthosts}}
same_domain_copy_routing
no_verify
no_more
----------------------------8< cut here >8------------------------------
The route_data extracts the 'host' field from the smarthosts file;
address_data associates the entire line from smarthosts with the
address, for later extraction.
----------------------------8< cut here >8------------------------------
begin transports
remote_smtp:
driver = smtp
.ifndef TLS_ALLOWED_OUTBOUND
hosts_avoid_tls = *
.endif
hosts_require_tls = +tls_required_to
hosts_try_auth = +authenticate_attempt_to
smarthost_smtp:
driver = smtp
port = ${extract{port}{$address_data}{$value}{\
${extract{submission}{$address_data}{587}{25}}\
}}
hosts_require_tls = ${extract{tls}{$address_data}{*}{+tls_required_to}}
hosts_require_auth = ${extract{user}{$address_data}{*}{+authenticate_required_to}}
helo_data = ${extract{helo}{$address_data}{$value}{MYHELO_TO_SMARTHOST}}
----------------------------8< cut here >8------------------------------
The TLS_ALLOWED_OUTBOUND is something I might define on the command-line
to send mail with a queue-run to someone whose TLS is currently broken.
The hostlist authenticate_attempt_to is used for stuff not going via a
smarthost.
The hostlists tls_required_to and authenticate_required_to are fallbacks
for when the fields are not present. You can easily remove those and
just have no coerced default. Note the default HELO parameter is a
macro. No, none of the lines in the example smarthosts file set helo,
so I always use that default.
For the authenticators, I'll remove the server_* fields which aren't
relevant; in theory I might start my laptop's Exim accepting remote mail
from the local network, authenticated, and send via that. I've done
that once, maybe twice, so it's just a distraction here. But if you do
want to handle authentication server-side, you just add the server_*
fields to these same authenticators.
----------------------------8< cut here >8------------------------------
begin authenticators
auth_cram:
driver = cram_md5
public_name = CRAM-MD5
# If smarthosts address_data gives us a user, use that; else do
# a domain search on client-passwords (no * default support)
client_name = ${extract{user}{$address_data}{$value}{\
${extract{user}{${lookup{$host}partial()lsearch{RUNAUTHDIR/client-passwords}}}{$value}fail}}}
# The password, however, always comes from client-passwords
client_secret = ${extract{password}{${lookup{\
${extract{user}{$address_data}{$value}{$host}}\
}partial()lsearch{RUNAUTHDIR/client-passwords}}}{$value}fail}
auth_plain:
driver = plaintext
public_name = PLAIN
client_condition = ${if def:tls_cipher}
client_send = ^${extract{user}{$address_data}{$value}{\
${extract{user}{${lookup{$host}partial()lsearch{RUNAUTHDIR/client-passwords}}}{$value}fail}}}\
^${extract{password}{${lookup{\
${extract{user}{$address_data}{$value}{$host}}\
}partial()lsearch{RUNAUTHDIR/client-passwords}}}{$value}fail}
----------------------------8< cut here >8------------------------------
There's no GSSAPI support client-side because I only use that with
GSSAPI-enabled MUAs, not from an MTA. I could create a server principal
with no bound address, I suppose, but I don't want to.
I think I got the full details.