How to config standard SMTP Smarthost with auth for outgoing mail?

Hi all.

Has anyone successfully configured exim on Hestia to connect to a standard SMTP smarthost relay service? (Not Amazon SES. That config hasn’t worked at all.)

I’ve got a Debian 10 server running Hestia 1.2.3 on AT&T Fiber at my house, but AT&T block port 25 for outgoing connections for residential service. So I’m trying to use dnsexit.com’s mail relay service. This is just a typical SMTP smarthost: you can choose from a list of ports to find one that your ISP doesn’t block, it supports STARTTLS, you set up a username and password for the service so you have to set up your MTA to connect with TLS and a basic SMTP username/password. Dnsexit.com supplies example of configuring various mail clients to connect to relay.dnsexit.com and example configs for Exchange, postfix, and sendmail—but NOT one for exim! (I’ve written to them to ask why they’re missing one for exim.)

So far, everything I’ve tried in exim configuration has failed to authenticate with relay.dnsexit.com server. It’s connecting to relay.dnsexit.com, but I’m just getting “Relay access denied” every time. (And yes, I’ve quadruple checked that I have my username/password right :smile: .)

So here’s where I’m at so far. I’ve copied some of the config from the default exim4.conf.template and from Debian’s default version of the exim config, including their use of a file named /etc/exim4/passwd.client to store the username/password for the remote host.

ROUTER_SMARTHOST = relay.dnsexit.com
SMARTHOST_PORT = 587

. . .

begin routers

.ifdef ROUTER_SMARTHOST

smarthost:
  driver = manualroute
  domains = ! +local_domains
  transport = smarthost_with_auth
  route_data = ROUTER_SMARTHOST
  ignore_target_hosts = <; 0.0.0.0 ; 127.0.0.0/8 ; ::1
  no_more

.else

dnslookup:
  driver = dnslookup
  domains = !+local_domains
  transport = remote_smtp
  no_more

.endif

. . .

begin transports

.ifdef ROUTER_SMARTHOST

remote_smarthost:
  driver = smtp
  message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
  multi_domain
  hosts_require_tls = *
  tls_verify_hosts = *
  tls_sni = ROUTER_SMARTHOST

  hosts_try_auth = <; ${if exists{CONFDIR/passwd.client}{${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$host_address}}}{}}

  .ifdef SMARTHOST_PORT
  port = SMARTHOST_PORT
  .endif
  .ifdef _HAVE_OPENSSL
  tls_require_ciphers = HIGH:!aNULL:@STRENGTH
  .endif
  .ifdef _HAVE_GNUTLS
  tls_require_ciphers = SECURE192:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1
  .endif

.endif

. . .

begin authenticators
                                                                  
cram_md5:                                                          
  driver = cram_md5                                          
  public_name = CRAM-MD5
  client_name = ${extract{1}{:}{${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$value}fail}}}
  client_secret = ${extract{2}{:}{${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$value}fail}}}

# This returns the matching line from passwd.client and doubles all ^
# for use by the next two authenticators
PASSWDLINE=${sg{${lookup{$host}nwildlsearch{CONFDIR/passwd.client}{$value}fail}}{\\N[\\^]\\N}{^^}}
                                     
plain:                        
  driver = plaintext          
  public_name = PLAIN         
  client_send = "<; ${if !eq{$tls_out_cipher}{}{^${extract{1}{:}{PASSWDLINE}}^${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}}fail}" 
  
login:
  driver = plaintext
  public_name = LOGIN
  # Return empty string if not non-TLS AND looking up $host in passwd-file
  # yields a non-empty string; fail otherwise.
  client_send = "<; ${if and{{!eq{$tls_out_cipher}{}}{!eq{PASSWDLINE}{}}}{}fail}; ${extract{1}{::}{PASSWDLINE}}; ${sg{PASSWDLINE}{\\N([^:]+:)(.*)\\N}{\\$2}}"

Thanks!
–Dan

hey dan!

we have a thread somewhere, with different config for different relays. I do have Amazon SES in place at a few servers, so I can asure that it works. however, depending in the service you use, you might need to validate your domains and more - esp ses is complex on that, so I understand if it’s not your first choice :wink:

if I find the thread, I’ll link it… however if I remember right it was pretty much straightforward from the ses for exim docs, so I think that should work for other services as well.

edit: here you go How to configure HestiaCP / Exim 4 for SMTP Relay (SendGrid, Mailgun, Amazon SES, etc)

PS: basically much less than what you all have - just an authenticator, a router and a transport…

1 Like

Well shit. :crazy_face:
HAHAHAHA!!

All that time trying to figure this out, and it was so simple. I think the complexity of the default Debian exim4.conf.template led me to think it was much more complicated than it is. (That and even the exim documentation shows all kinds of different ways to configure smarthosts.) I just copied the config from the solution on that thread, changed “mailjet” to just “smarthost”, and set my username and password for relay.dnsexit.com, and it worked just fine.

Thanks for finding that thread, @falzo! I don’t know how I didn’t come across it when I was searching the forums for messages about this.

Cheers
–Dan

1 Like

Here’s what I ended up doing, to make it a little more generic rather than specific to one relay service:

Edit /etc/exim4/exim4.conf.template

(1) At top, after the spam and clamd macros, add the following macros, changing the values to your relay service details:

SMARTHOST_ADDR = your.relay.service.com
SMARTHOST_PORT = 587
SMARTHOST_USER = yourusername
SMARTHOST_PASS = yourpassword

(2) Under “begin authenticators” add the following (order doesn’t matter):

.ifdef SMARTHOST_ADDR
smarthost_login:                            
  driver = plaintext                    
  public_name = LOGIN           
  client_send =:SMARTHOST_USER:SMARTHOST_PASS
.endif                                                                                                                                      

(3) Under “begin routers” add the following lines before the “dnslookup” router (order matters in the routers section):

.ifdef SMARTHOST_ADDR
smarthost:
  driver = manualroute
  domains = ! +local_domains
  transport = smarthost_smtp
  route_list = * SMARTHOST_ADDR
  no_verify
  no_more
.endif

(4) Under “begin transports” add the following (order doesn’t matter):

.ifdef SMARTHOST_ADDR
smarthost_smtp:
  driver = smtp
  .ifdef SMARTHOST_PORT
  port = SMARTHOST_PORT
  .endif
  hosts_require_auth = *
  hosts_require_tls = *
.endif

(5) Restart exim

Here’s another question:
The exim documentation says to use either the smarthost router or the dnslookup router, for non-local email. If that is the case, should the “redirect_router = dnslookup” lines within the “aliases” and “catchall” routers be changed to the following?

  .ifdef SMARTHOST_ADDR
  redirect_router = smarthost
  .else
  redirect_router = dnslookup
  .endif

Thanks
–Dan

4 Likes

thanks for sharing! for your last question I don’t have a proper answer though, as I simply haven’t messed around with that. as long as it is working I wouldn’t touch what’s in there per default :wink: :wink: