HTTPoison.Error sending a mail with Brevo : {:options, :incompatible, [verify: :verify_peer, cacerts: :undefined]}

Hi everyone,

Recently, our transactional emails won’t launch and return HTTPoison.Error like :
%HTTPoison.Error{reason: {:options, :incompatible, [verify: :verify_peer, cacerts: :undefined]}, id: nil}

I’m using the Brevo API V3. And my guess is that’s a problem with SSL; I currently use [ssl: [{:versions, [:"tlsv1.2"]}]].

Any idea or lead to help me on this case?

Thanks.

UPDATE :
Linked to OTP 26 upgrade. I obtain some progress by changing my request otps like :

  def process_request_options(_options) do
    [
      ssl: [
        verify: :verify_peer,
        cacerts: :public_key.cacerts_get(),
        versions: [:"tlsv1.2"]
      ]
    ]

Now the error is :
%HTTPoison.Error{reason: {:tls_alert, {:handshake_failure, ~c"TLS client: In state certify at ssl_handshake.erl:2140 generated CLIENT ALERT: Fatal - Handshake Failure\n {bad_cert,hostname_check_failed}"}}, id: nil}

Have you upgraded to OTP-26? You can read about the new default feature introduced to OTP-26: Erlang/OTP 26 Highlights - Erlang/OTP

Thanks @D4no0 , it’s surely that I upgraded recently to OTP 26.

Do you have any resources on how this translated into Elixir?

I suppose it’s something to change in Application.ensure_all_started(:ssl)?

I tried :

 config :my_app, MyApp.Mailer,
    [...]
    allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"],
    ssl: true,
    ssl_opts: [verify: :verify_peer, cacerts: :public_key.cacerts_get()],

Waiting for deploy on staging to see if it works. But does this seem like the right approach to you?

EDIT: No, sadly it didn’t change anything.

We use Finch with Brevo, we recently upgraded to Elixir 1.15.4 and OTP 26.0.2 and it works:

Finch.build(
   :delete,
   "https://api.sendinblue.com/v3/contacts/#{email}",
   [
      {"api-key", api_key()},
      {"content-type", "application/json"}
    ]
  )
 |> Finch.request(PlatformFinch)
 finch 0.16.0
 ssl_verify_fun 1.1.6
``
1 Like

I obtain some progress by changing my request otps like :

  def process_request_options(_options) do
    [
      ssl: [
        verify: :verify_peer,
        cacerts: :public_key.cacerts_get(),
        versions: [:"tlsv1.2"]
      ]
    ]

Now the error is :
%HTTPoison.Error{reason: {:tls_alert, {:handshake_failure, ~c"TLS client: In state certify at ssl_handshake.erl:2140 generated CLIENT ALERT: Fatal - Handshake Failure\n {bad_cert,hostname_check_failed}"}}, id: nil}

:wave: @GoulvenClech

Note that for wildcard certs you need to add an additional option, :customize_hostname_check

[
  ssl: [
    verify: :verify_peer,
    cacerts: :public_key.cacerts_get(),
    versions: [:"tlsv1.2"],
    customize_hostname_check: [
      match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
    ]
  ]
]

More info: Erlang standard library: ssl | EEF Security WG (note the depth option as well)

And for :public_key.cacerts_get() to work, you might need to first :public_key.cacerts_load() the certs (e.g. during application startup). Right now in your case it seems to be returning :undefined.

4 Likes

It looks like it was that!

Thanks a lot @ruslandoga , I clearly pay my lack of understanding of SSL and how OTP deal with it. I’ll work on that.