OrchardCMS / OrchardCore

Orchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.
https://orchardcore.net
BSD 3-Clause "New" or "Revised" License
7.44k stars 2.4k forks source link

Can't send email using Office365 account #3556

Closed jonvee closed 5 years ago

jonvee commented 5 years ago

SMTP client fails due to missing automatic migration

hishamco commented 5 years ago

Which migration code that you are talking about? What is the steps to reproduce the issue?

jonvee commented 5 years ago

@sebastienros seemed to know what was missing on the dev branch - "we changed the smtp client that is used, didn't think it would cause a migration issue on the dev branch at least" Repro, start with a build prior to the smtp client change, configure & test smtp successfully, update nuget and smtp fails. Error message: An error occurred while sending an email: 'An error occurred while attempting to establish an SSL or TLS connection. One possibility is that you are trying to connect to a port which does not support SSL/TLS. The other possibility is that the SSL certificate presented by the server is not trusted by the system for one or more of the following reasons: 1. The server is using a self-signed certificate which cannot be verified. 2. The local system is missing a Root or Intermediate certificate needed to verify the server's certificate. 3. The certificate presented by the server is expired or invalid. See https://github.com/jstedfast/MailKit/blob/master/FAQ.md#InvalidSslCertificate for possible solutions.'

hishamco commented 5 years ago

we changed the smtp client that is used, didn't think it would cause a migration issue on the dev branch at least

I am the one who made this change 😊 that is why I am interested on this

Thanks for the details explanation, seems I can't test this while it requires a certificate stuff, I will wait for @sebastienros because he knows the details as you mentioned

sebastienros commented 5 years ago

This might be a problem with the code, see this section: https://github.com/jstedfast/MailKit/blob/master/FAQ.md#1-the-mail-server-does-not-support-ssl-on-the-specified-port

sebastienros commented 5 years ago

Can you give more information about the host you are connecting to?

jonvee commented 5 years ago

smtp.office365.com port 587 O365 user & pass

jonvee commented 5 years ago

Just tested another project and the same account and settings work on earlier builds

sebastienros commented 5 years ago

Thanks I think I can try that, unless @hishamco does it too if he has an office365 account

hishamco commented 5 years ago

Unfortunately I didn't have an account, but I think I can test this case if I'm using my Gmail account. Am I right?

sebastienros commented 5 years ago

we should also test gmail, right, I will test office and see what's missing.

jonvee commented 5 years ago

Not sure if this is relevant, but I was doing some googling... MailKit C# SmtpClient.Connect() to Office 365 generating exception "Handshake failed due to an unexpected packet format The solution is to connect to Office 365 like this instead: smtpClient.Connect("smtp.office365.com", 587, SecureSocketOptions.StartTls);"

jonvee commented 5 years ago

After a bit more searching I believe this is due to the authentication using ssl rather than TLS which is what O365 wants (even though their docs don't really mention it). I'm assuming an option to select the authentication mode (SSL:true, TLS:SecureSocketOptions.StartTls) needs to be added to settings, but I don't know how to tackle this one..?

jonvee commented 5 years ago

Gmail will be completely different since it require OAuth or a few tweaks to the gmail account (enable less secure apps, etc.)

hishamco commented 5 years ago

@jonvee could you try this in the source code client.AuthenticationMechanisms.Remove("XOAUTH2") after connecting but before authenticating

jonvee commented 5 years ago

I added client.AuthenticationMechanisms.Remove("XOAUTH2"); to line 137 in SmtpService.cs but that made no difference for O365, I'm not using Gmail so I'm not sure if that's what needed there or not.

MichaelPetrinolis commented 5 years ago

Why not use use something like that await client.ConnectAsync(_options.Host, _options.Port, _options.EnableSsl ? SecureSocketOptions.Auto : SecureSocketOptions.None);
(i did not test it , i don't have an O365 account) , see https://github.com/jstedfast/MailKit/blob/e9dee7febf94b1e75b0db070e02c9b61115a830f/MailKit/Net/Smtp/SmtpClient.cs#L1340 it will use the protocol based on port. Later, if issues encountered, we could explicit add the secure protocol in settings.

more info : https://www.fastmail.com/help/technical/ssltlsstarttls.html

jonvee commented 5 years ago

I'm not sure if that's correct or not, but the error is slightly different now: "An error occurred while sending an email: 'An error occurred while attempting to establish an SSL or TLS connection. The SSL certificate presented by the server is not trusted by the system for one or more of the following reasons: 1. The server is using a self-signed certificate which cannot be verified. 2. The local system is missing a Root or Intermediate certificate needed to verify the server's certificate. 3. The certificate presented by the server is expired or invalid. See https://github.com/jstedfast/MailKit/blob/master/FAQ.md#InvalidSslCertificate for possible solutions.'" So it may be that NOW it fails due to using a self-signed cert..? I can't test a legit cert without putting it on a production domain, so I'm not sure how to test or even move forward. @sebastienros Any suggestions?

MichaelPetrinolis commented 5 years ago

If it is due to invalid ssl certificate, as the article explains, if you add this before client.ConnectAsync in OrchardCore.Email would fix your issue

    client.ServerCertificateValidationCallback = (s,c,h,e) => true;

But it is not recommended, so it is better to test with smtp4dev or temp folder and go live with valid certs on SMTP server

jonvee commented 5 years ago

If the error is talking about the cert on the SMTP server, then I misunderstood, I thought it was talking about the website/orchard cert. I'm sure O365 is using using a valid certs

MichaelPetrinolis commented 5 years ago

I have not test it, but from my understanding, the client does not trust the certificate presented by the remote machine (as long as the STARTTLS option is used). If you can build from source and use the generated packages, you could test the SecureSocketOptions.Auto in conjuction with ServerCertificateValidationCallback mentioned previously in the thread.

jonvee commented 5 years ago

Sadly I'm just getting my head around theming and templates so I'm not sure how to tackle this issue... I just brought it up on Gitter and filed it. I found some info from googling, but I really have no idea how to debug or test this module or its underlying features.

MichaelPetrinolis commented 5 years ago

no worries, it will be fixed :)

MichaelPetrinolis commented 5 years ago

@jonvee I just tested with an O365 account. If you set SSL to true, you instruct the smtp client to establish an SSL transport connection, which is not the case for office 365 and you receive the error message you mentioned. I unchecked the SSL option, and it worked - with the latest sources

jonvee commented 5 years ago

Leaving SSL unchecked using latest beta3-71319 Nuget packages on a new app gives the same error... I'll try with a source clone now.

jonvee commented 5 years ago

Same results :( Works fine with last "stable beta" release & ssl checked (nuget beta3-71077, not dev)

MichaelPetrinolis commented 5 years ago

Hi @jonvee , when you get some time could you please replace the smtpservice.cs in OrchardCore.Email.Services with the one in the zip file for test? Also enable the SSL flag in SMTP settings If this works, i can send a PR SmtpService.zip

jonvee commented 5 years ago

Thanks @MichaelPetrinolis !!! Works great!

MichaelPetrinolis commented 5 years ago

Cool, I will create a PR. The suggestion is to rename enablessl to auto configuration, and add another setting eg socket option which will default to none, and have possible values none, TLS, SSL and STARTTLS.

sebastienros commented 5 years ago

Awesome guys, thanks a lot

jonvee commented 5 years ago

@MichaelPetrinolis @sebastienros Since the merged changes, I'm seeing the same errors again.

MichaelPetrinolis commented 5 years ago

@jonvee the difference between the dev version and the one in the zip is in these lines client.ServerCertificateValidationCallback = (s, c, h, e) => { _logger.LogInformation("SMTP Server's Certificate was invalid, will force it valid"); return true; }; in the SendOnlineMessage function. If this is the case, then the machine that runs OC and tries to send the email, does not accept the server's certificate. I suggest to check the clock of the machine, and the list of trusted roots certificates. It is not wise to override the certificate validation on production machines

jonvee commented 5 years ago

Sorry for the delayed reply. This doesn't really make any sense to me. I should be able to use an office365 account without jumping through any hoops. It works in previous versions, it works on other apps and I just don't understand why there are any issues at all. I'm not using an SMTP relay, I'm authenticating a user, just like any mail app. Wish I new how to debug this, but I don't so until someone else demonstrates how to use an O365 account to send mail I can't even use the dev branch to test workflows, forms or user registrations.

Skrypt commented 5 years ago

I'm using it with latest changes and it seems to work with office 365.

sebastienros commented 5 years ago

@Skrypt can you take screenshots of your settigns for @jonvee ?

Skrypt commented 5 years ago

BTW "Locataire" for "Tenant" translation sounds weird to me.

sebastienros commented 5 years ago

C'est beau! Merci @agriffard

Skrypt commented 5 years ago

C'est une traduction parfaite, ça y'a pas de doute. Je suis probablement pas habitué au terme français. "Tenant" pour moi me semble plus distinctif du fait que c'est une instance de site web... tandis que "Locataire" je me demande "Locataire de quoi" ? Et une location c'est comme un espace "emprunté" alors qu'ici c'est un espace bien déterminé et qui n'a pas de sens rapproché avec "Locataire". Bah... du coup je vais m'habituer ! Merci @agriffard 😄

jonvee commented 5 years ago

Ya, those settings don't work, tried with multiple O365 accounts in completely disparate subscriptions. Not sure which Root or Intermediate certificates are missing locally as I'm sure smtp.office365.com is using valid certs. Should I try a complete reinstall of VS? I haven't upgraded to VS 2019 yet, should I?

Skrypt commented 5 years ago

My website is on Azure is it your case?

jonvee commented 5 years ago

I'm testing locally...

jonvee commented 5 years ago

I have few VMs running IIS in azure, but haven't actually tried deploying as an azure web app

Skrypt commented 5 years ago

Ok, that may be the issue. You need to test it on your server else the O365 server might refuse simply the email because of his spam policies.

jonvee commented 5 years ago

That's not ideal for dev/testing but I'll try it now and let you know.

Skrypt commented 5 years ago

For dev/testing you should never really send emails ; that's why we added the local folder as an option.

Skrypt commented 5 years ago

The VMs running IIS in Azure should work since they should use trusted IP addresses.

sebastienros commented 5 years ago

@Skrypt you still want to know if your settings are correct before deploying. The issue with spam detection is that there isn't much to do against it.

Skrypt commented 5 years ago

I can try locally if you want too. I will test it and report what I found here.

Skrypt commented 5 years ago

Worked for me from localhost.

Skrypt commented 5 years ago

At this point the only thing I can think of is that his internet provider is preventing the use of port 587. ~You could try port 993 which is the IMAP port~.

jonvee commented 5 years ago

Unfortunately the best I can do is use a self-signed cert on a production server which yields the same results as locally. Without purchasing a domain and ssl for testing I can't do much more and I'm not about to do that for every project I'm working on.