managua1902

managua1902

Unable to send an email via my SMTP server via SSL/TLS. But my local email client works well

I have my own SMTP server. It’s behind SSL/TLS - port 465

In my phoenix I use Swoosh to send emails. Since recently I’ve been facing this error:

delivery error:
{:retries_exceeded, {:network_failure, ~c"mail.my_mail_server.com", {:error, {:options, :incompatible, [verify: :verify_peer, cacerts: :undefined]}}}}

My config:

adapter: Swoosh.Adapters.SMTP,
    relay: host,
    username: user,
    password: password,
    port: port,

    ssl: true,
    tls: :always,

    # allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2", :"tlsv1.3"],
    auth: :always,
    retries: 5,
    no_mx_lookups: true,


    ssl: [
    # ssl_opts: [
    # ssl_options: [

        verify: :verify_none,
      # verify: :verify_peer,

      # cacerts: :public_key.cacerts_get(),
      # versions: [:"tlsv1.2"],
      # versions: [:"tlsv1.3"],
      #   customize_hostname_check: [
      #     match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
      #   ]
    ],

    tls_options: [
        # verify: :verify_peer,
        verify: :verify_none,

        # cacerts: :certifi.cacerts(),
        # cacerts: :public_key.cacerts_get(),
        #   server_name_indication: ~c"#{host}",
    ]

An interesting thing is that all the options that have to do with tls and ssl will be ignored.

Meaning, the error will always contain

<...> { verify: :verify_peer, cacerts: :undefined}...

There’s never been an error with verify: :verify_none and cacerts: <something_else>, even though I’ve set it up.

Why? I’ve set different values in the config. Why will they remain verify: :verify_peer, cacerts: :undefined ?

And it’s unclear wether I should used ssl_opts, ssl or ssl_options – I’ve tried dozens of combinations. The same goes for the tls_options.

What’s the matter?


The emails I’ll send from an email-client from my local computer via the same email server get sent with no issue, and under the same settings: port 465, SSL/TLS, same relay.

P.S.

OTP 26.

I’m aware of this - Erlang/OTP 26 Highlights - Erlang/OTP

But, as I’ve mentioned, it’ll ignore my verify: <...> variables in the first place.

Most Liked

_jonas

_jonas

I was also struggling with this issue for a good while until I used almost the exact configuration mentioned here by @LostKobrakai SSL connection options · Issue #298 · gen-smtp/gen_smtp · GitHub

Here is my config which now (finally) works (using this smtp server)

  config :backend, Backend.Mailer,
    adapter: Swoosh.Adapters.SMTP,
    relay: System.get_env("EMAIL_SMTP_HOST"),
    username: System.get_env("EMAIL_SMTP_USER"),
    password: System.get_env("EMAIL_SMTP_PASSWORD"),
    port: String.to_integer(System.get_env("EMAIL_SMTP_PORT") || "465"),
    ssl: true,
    tls: :never,
    auth: :always,
    retries: 2,
    no_mx_lookups: false,
    sockopts: [
      versions: [:"tlsv1.2", :"tlsv1.3"],
      verify: :verify_peer,
      cacerts: :public_key.cacerts_get(),
      depth: 3,
      customize_hostname_check: [
        match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
      ],
      server_name_indication: 'mail.privateemail.com'
    ]

It was pretty tough to figure this out as someone very new to Elixir, especially since I couldn’t find this sockopts key documented anywhere in Swoosh or the gen_smtp Readme and I still don’t really understand why this is necessary, but maybe it helps someone.
What was also really tripping me up for a bit was the fact that server_name_indication apparently needs to be a charlist (single quoted) and I was trying to set it as a string with System.get_env("EMAIL_SMTP_HOST").

Perhaps someone who understands this better than me could add a note about it to the Swoosh SMTP adapter docs, since without these settings it doesn’t seem to be possible to get it to work?

LostKobrakai

LostKobrakai

I might be able to give some insight around the why here: Erlangs SSL handling is a lot more explicit (and hence complicated) than in many other places. Given nowadays emails usually use SSL over starttls you’re running into that explicitness. That’s most of the reason for the sockopts. More info can be found here: Erlang standard library: ssl | EEF Security WG

server_name_indication is additional required because by default (no_mx_lookup: false) gen_smtp doesn’t connect to the smtp server using the provided hostname, but rather it looks up the IP address for the hostname using the MX dns entry and uses that IP to connect to the server. Usually SSL certificates are supplied for a given hostname though, not an IP address. Therefore one needs to supply the hostname as SNI value, so the certificate can be validated against that hostname instead.

Disabling MX lookup does remove the need for the SNI value.

LostKobrakai

LostKobrakai

The :tls setting is for STARTTLS. If you’re not using starttls you should disable it. You can find a bit more context about that here: SSL connection options · Issue #298 · gen-smtp/gen_smtp · GitHub

al2o3cr

al2o3cr

What version of OTP are you on? Have you upgraded recently?

Asking because there’s a fix that just landed for TLSv1.3 in OTP 25 + 26:

silverdr

silverdr

FWIW - 26.2.5 images with Elixir 1.16.2 are available now for over a week. My problem was indeed caused by that OTP 25/26 bug but… for “posterity” it was not enough to just replace OTP with 26.2.5!

Once I did built the “runner” image with 26.2.5 it started throwing another error, namely a

- {:bad_cert, :max_path_length_reached}

one, which of course was never a problem before :wink: Luckily this one was much easier to find a solution to. Going to Erlang -- ssl and doing search for “path” revealed

https://www.erlang.org/doc/man/ssl#type-allowed_cert_chain_length

which talks about “depth” so searching for “depth” lead me to an option in common_option, which given a nice, round number of 64 cured the setup. Thus my current (working) prod config – if somebody ever needs hints is:

	config :my_app, MyApp.Mailer,
		adapter: Swoosh.Adapters.SMTP,
		relay: System.get_env("SMTP_RELAY", "mail.myapp.com"),
		hostname: System.get_env("SMTP_HOSTNAME", "mail.mysmtpserver.com"),
		username: System.get_env("SMTP_USERNAME", "no-reply@myapp.com"),
		password: System.get_env("SMTP_PASSWORD"),
		auth: :always,
		ssl: false,
		tls: :always,
		tls_options: [
			versions: [:"tlsv1.3"],
			cacerts: :public_key.cacerts_get(),
			server_name_indication: 'mail.mysmtpserver.com', # what your certificate is issued for
			depth: 64, # important or stuff may crash with - {:bad_cert, :max_path_length_reached}
		],
		port: 587,
		retries: 2

hostnames and application name are “dummies” of course.

:bowing_man: to @al2o3cr the umpteenth time :slight_smile:

Where Next?

Popular in Questions Top

Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
dokuzbir
Hello, I am trying to convert my lists to string without losing brackets.For start i have 3 map. They look like these buyer = %{ id: ...
New
Phillipp
Hey, I have a NanoPi-M3 and try to install Elixir on their Ubuntu image. I followed the Raspberry Pi installation instructions from the ...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New

Other popular topics Top

belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New

We're in Beta

About us Mission Statement