Custom email: Net::SMTP doesn't select the correct authentication method automatically
From the feedback issue:
Problem
I set up a Microsoft account myself and configured everything accordingly. It didn't work.
What's really interesting is, that it used to work, when I tried it before release. Maybe something in the configuration or the system itself changed
A short recap of how I configured it and what I tried
- Enable Authenticated SMTP for the user in question (via the user flyout, Email and Apps section)
- Enable 2FA for that account in Active Directory (now Entra).
- Set
Set-TransportConfig -SmtpClientAuthenticationDisabled $false
via Azure Cloud Shell. - Also tried
Set-TransportConfig -AllowLegacyTLSClients $true
(reference) - Allow app password (via Entra admin center --> Named locations --> Configure MFA trusted IPs. (reference)
- Sign in to the "custom email" account and configure 2FA (for example TOTP using an authenticator app) via Security Info.
- Add an app password for that account on the same page. (reference)
- I also configured a transport rule, but I didn't get so far, so that's optional for now.
- Check credentials using
swaks
like mentioned in the comment above. It works!swaks --to user@example.com --from marc.saleiko@XYZ.onmicrosoft.com --auth-user marc.saleiko@XYZ.onmicrosoft.com --server smtp.office365.com:587 -tls-optional --auth-password superapppassword
-tls-optional
because that's closest to the setup we use internally. - Used the same credentials for the custom email configuration in my local environment.
500
error after a few seconds, because we don't catch the read timeout error yet. - I increased the read timeout locally and repeated the last step.
- Now we get a different error
504 5.7.4 Unrecognized authentication type
. Looks like Microsoft wants explicit TLS. Tried that, but it also didn't work.
Replication and testing
Feel free to use this sample script to run tests on your own:
smtp_options = {
user_name: '',
password: '',
address: 'smtp.office365.com',
port: 587,
read_timeout: 7
}
recipient = 'name@gitlab.com'
mail = Mail.new do
from smtp_options[:user_name]
to recipient
subject 'M365 test email'
body 'test content'
end
mail.delivery_method(::Mail::SMTP, smtp_options)
mail.deliver
Basic Authenticated SMTP setup:
- Server:
smtp.office365.com
- Port:
587
(recommended) or port25
- TLS/StartTLS:
Enabled
- Username/email address and password: Enter the sign-in credentials of the hosted mailbox being used
Solution path
- We require the SMTP server to return a list of AUTH types in the handshake phase. E.g.
250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
- ActionMailer will then pick one method and send the request.
- If will fail with
Net::SMTPAuthenticationError: 504 5.7.4 Unrecognized authentication type
if no list is provided. - Microsoft 365 doesn't provide such a list.
- Setting
authentication: :login
on the SMTP settings works, but needs to be set explicitly. - So we probably need an additional setting where maintainers+ can set an authentication method explicitly or let the server decide which to choose.
- This will also be a great addition for customers of other service providers where the server also doesn't return a list or they want to use some challenge based AUTh method like
cram_md5
.
Edited by Marc Saleiko