-
Notifications
You must be signed in to change notification settings - Fork 266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TLS + SMTP Error when using OTP/26 #785 #328
Comments
Well, the TLS certificate validation could easily be the root cause. Wihout looking into details, may you try to add following options to gen_smtp client? [{tls_options, [{verify, verify_none}]}] |
@seriyps Thanks, that worked - now the emails send again. Maybe Also do you have an idea why that happens, given that the SMTP server's certificate is valid? "Normal" email clients like Outlook or Apple Mail have no issues, and openssl also says the certificate is valid.
Or am I misunderstanding something here? |
I think this document describes this topic quite well https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/ssl In short, even when SMTP server has a certificate that is signed by a trusted issuer, you should tell Erlang's |
Thanks for the link, I checked it out - however trying For more detail: Adding the
Now that's something I am familiar with, and in the past i used the PS: this issue occurs on both macOS 13 and Debian 11. I also tried sending via gmail (smtp.gmail.com) and get the same issues - so I doubt it has anything to do with the smtp server I'm using. |
Sorry, I don't have a good tips for you. You can try to enable debug logging for OTP ssl app, but I don't remember all the options you should tweak to do that... I think smth like
|
No worries, thanks anyways for your quick replies! I tried the setting the log level or using ssl:connect, but the log level doesn't change anything ( I already have the global log level set to debug) and ssl:connect doesnt show the same errors. I concede that for now STARTTLS doesn't seem to work with OTP/26 unless you set |
nope, it was just non-fatal error prior to OTP-26 |
I did some more digging in the documentation and created a quick reproduction script. Mix.install([
{:gen_smtp, "~> 1.2"},
{:certifi, "~> 2.11"},
{:eiconv, "~> 1.0"}
])
require Logger
:application.ensure_all_started(:ssl)
Logger.configure(level: :debug)
:logger.set_application_level(:ssl, :debug)
Logger.debug("Starting SMTP TLS test")
{:ok, pid} =
:gen_smtp_client.send(
{"[email protected]", ["[email protected]"],
"Subject: testing\r\nFrom: Test <[email protected]>\r\nTo: Test <[email protected]>\r\n\r\nThis is the email body"},
relay: "smtp.gmail.com",
retries: 0,
tls: :always,
ssl: false,
auth: :always,
port: 587,
username: "[email protected]",
password: "test",
tls_options: [
verify: :verify_peer,
cacerts: :certifi.cacerts(), # <--- this is required!
server_name_indication: ~c"smtp.gmail.com", # <--- this is required!
depth: 99,
log_level: :debug
]
)
Process.monitor(pid)
receive do
_ ->
:ok
end Now returns The important parts are: cacerts: :certifi.cacerts(), # <--- this is required!
server_name_indication: ~c"smtp.gmail.com", # <--- this is required! I'm using @seriyps what do you think - maybe we should use those options per default, or otherwise maybe mention this in the documentation? I'd be happy to open a PR for this! |
I think mentioning it in the docs should be the solution - pre-selecting the list of trusted root certificates might be not very secure plus only works without dependencies on OTP-25+ @mworrell WDYT? |
I am actually ok with a default using the list from A lot of projects started to include this app, and it is quite good maintained. If we have a loose dependency, like: {tls_certificate_check, "~> 1.18"}, Then the project using gen_smtp can always use a newer version. Example of the usage: (zotonic@PoToi)17> tls_certificate_check:options("smtp.gmail.com").
[{verify,verify_peer},
{depth,100},
{cacerts,[<<48,130,3,117,48,130,2,93,160,3,2,1,2,2,11,4,0,
0,0,0,1,21,75,...>>,
<<48,130,4,42,48,130,3,18,160,3,2,1,2,2,4,56,99,222,248,
48,13,6,...>>,
<<48,130,3,119,48,130,2,95,160,3,2,1,2,2,4,2,0,0,185,48,
13,...>>,
<<48,130,4,145,48,130,3,121,160,3,2,1,2,2,4,69,107,80,84,
48,...>>,
<<48,130,4,50,48,130,3,26,160,3,2,1,2,2,1,1,48,13,6,...>>,
<<48,130,5,183,48,130,3,159,160,3,2,1,2,2,2,5,9,48,...>>,
<<48,130,6,157,48,130,4,133,160,3,2,1,2,2,2,5,198,...>>,
<<48,130,3,90,48,130,2,66,160,3,2,1,2,2,1,0,...>>,
<<48,130,4,48,48,130,3,24,160,3,2,1,2,2,16,...>>,
<<48,130,4,0,48,130,2,232,160,3,2,1,2,2,...>>,
<<48,130,4,15,48,130,2,247,160,3,2,1,2,...>>,
<<48,130,3,183,48,130,2,159,160,3,2,1,...>>,
<<48,130,3,175,48,130,2,151,160,3,2,...>>,
<<48,130,3,197,48,130,2,173,160,3,...>>,
<<48,130,5,186,48,130,3,162,160,...>>,
<<48,130,5,189,48,130,3,165,...>>,
<<48,130,3,184,48,130,2,...>>,
<<48,130,3,188,48,130,...>>,
<<48,130,4,29,48,...>>,
<<48,130,2,137,...>>,
<<48,130,3,...>>,
<<48,130,...>>,
<<"0"...>>,<<...>>|...]},
{verify_fun,{fun ssl_verify_hostname:verify_fun/3,
[{check_hostname,"smtp.gmail.com"}]}},
{partial_chain,fun tls_certificate_check_shared_state:find_trusted_authority/1},
{customize_hostname_check,[{match_fun,#Fun<public_key.6.103305546>}]},
{server_name_indication,"smtp.gmail.com"}] |
I agree with both points - including this by default would make it easier for most people to use, however I also understand that, as I do however think that |
@fekle thanks for posting a workaround with explicitly specified options! It didn't work for me initially, as I decided not to specify the Before specifying the
After specifying the depth parameter, all worked as expected, and a "provider queue" string was returned:
My final code also doesn't depend on Mix.install([:gen_smtp])
:gen_smtp_client.send_blocking(
{"[email protected]", ["[email protected]"],
"Subject: Emails are working\r\nFrom: Eugene's App <[email protected]>\r\nTo: Eugene <[email protected]>\r\n\r\nLooks like emails are working"},
auth: :always,
relay: "smtp.sendgrid.net",
port: 587,
tls: :always,
username: "apikey",
password: "SG.YDst...",
tls_options: [
verify: :verify_peer,
cacerts: :public_key.cacerts_get(),
server_name_indication: 'smtp.sendgrid.net',
depth: 99
]
) |
Having spent some time with this I stumbled upon an interesting problem. We are using The server's certificate specifies Setting SNI ( Here is the full example for Microsoft365: Mix.install([:gen_smtp])
:gen_smtp_client.send_blocking(
{"[email protected]", ["[email protected]"],
"Subject: Emails are working\r\nFrom: Eugene's App <[email protected]>\r\nTo: Eugene <[email protected]>\r\n\r\nLooks like emails are working"},
auth: :always,
relay: "smtp.office365.com",
port: 587,
auth: :always,
ssl: false,
tls: :always,
username: "...",
password: "...",
tls_options: [
verify: :verify_peer,
versions: ["tlsv1.3"],
cacerts: public_key:cacerts_get(),
server_name_indication: "office365.com",
depth: 99
]
) |
@gmile you're welcome! :-) I didn't mark I ended up using what @mworrell showed, that works great with all checks: [...]
tls_options: :tls_certificate_check.options(System.get_env("SMTP_HOST"))
[...] Before we close this issue - should we now change the defaults in |
Very nice, did not know about Since OTP changed its defaults maybe it would be a good idea to change the defaults of |
In case anyone needs to get this working for AWS SES, this seems to be the minimal config... smtp_relay = System.get_env("AWS_SMTP_RELAY") # e.g. "email-smtp.us-east-1.amazonaws.com"
config = [
relay: smtp_relay,
port: 587,
username: System.get_env("AWS_SMTP_USERNAME"),
password: System.get_env("AWS_SMTP_PASSWORD"),
tls: :always,
tls_options: :tls_certificate_check.options(smtp_relay)
] |
I'm using tls_options: [
...
versions: ["tlsv1.2"],
server_name_indication: smtp_server |> to_charlist(),
...
] The SES endpoint only support TLS v1.2, I think. |
AWS SES worked for me like this in elixir:
|
Had to come back to this once more while upgrading an older app. My previous answer didn't immediately work anymore. ℹ️ It did worked after changing exactly two things:
The final code looks like this: Mix.install([:gen_smtp])
:gen_smtp_client.send_blocking(
{"[email protected]", ["[email protected]"],
"Subject: Emails are working\r\nFrom: Eugene's App <[email protected]>\r\nTo: Eugene <[email protected]>\r\n\r\nLooks like emails are working"},
auth: :always,
relay: System.get_env("SMTP_RELAY"),
port: 587,
tls: :always,
username: System.get_env("SMTP_USERNAME"),
password: System.get_env("SMTP_PASSWORD"),
tls_options: [
verify: :verify_peer,
cacerts: :public_key.cacerts_get(),
depth: 99,
server_name_indication: ~c"#{System.get_env("SMTP_RELAY")}",
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]
) As a side note, this code doesn't rely on On another separate note, this older app I was upgrading is using a regional, lesser known SMTP provider, so until I realized I needed to change from using IP to using a hostname, I was getting the |
OTP 26 changed the error level of what we're seeing when trying to send email to SES via TLS. This additional configuration should let us communicate via TLS without issues. See gen-smtp/gen_smtp#328
OTP 26 changed the error level of what we're seeing when trying to send email to SES via TLS. This additional configuration should let us communicate via TLS without issues. See gen-smtp/gen_smtp#328
Thanks, it helped me too! |
Describe the bug
Hi there - I already opened this issue in swoosh/swoosh#785 but it looks like it is related to
gen_smtp
, so I'll open it here as well.I recently updated my Projects to Elixir 1.15 and OTP/26, and everything but sending emails via swoosh and gen_smtp works fine.
I am sending E-Mails via SMTP, using a local business mail provider as a relay.
Swoosh tries sending the email multiple times via gen_smtp and finally fails with the following error:
Here is my configuration:
The provider only supports STARTTLS via port 587, so that's why
ssl
is set tofalse
.With Elixir 1.15 on OTP/25 it worked fine, with OTP/26 the issue appears.
I checked the Erlang documentation, but there don't seem to be any breaking changes related to TLS apart from SSL certificate validation being on by default, but that should be fine? I know this is not much to go on, but unfortunately swoosh does not give me any more information apart from
:tls_failed
which makes this hard to debug.Steps to Reproduce the Bug or Issue
Send an email via Swoosh's SMTP adapter and the aforementioned config with OTP/26.
Expected behavior
The email sends without issues.
Your reproducible example
No response
Screenshots or Videos
No response
Platform
Additional context
No response
The text was updated successfully, but these errors were encountered: