Mailkit The SMTP server has unexpectedly disconnected - asp.net-core

I deployed a ASP.NET Core 6 website on IONOS.
I try to send emails (with my IONOS email) to validate the email address of a new user with MailKit 3.4.3.
Locally everything works fine, the email is sent correctly. But when I deploy the site on IONOS I have an error during the connection :
Error : The SMTP server has unexpectedly disconnected.
Stack : at MailKit.Net.Smtp.SmtpStream.ReadAheadAsync(CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpStream.ReadResponseAsync(CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpClient.ConnectAsync(String host, Int32 port, SecureSocketOptions options, CancellationToken cancellationToken)
I contacted IONOS support several times, they confirm that the HOST address, the Port are correct and that there are no restrictions on their side, it should work...
My code :
using SmtpClient smtp = new(new ProtocolLogger("smtp.log"));
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
await smtp.ConnectAsync("mrelay.schlund.de", 587, SecureSocketOptions.StartTls);
await smtp.AuthenticateAsync(test#test.fr", "greatpwd");
smtp.Send(email);
smtp.Disconnect(true);
Any idea what I might be missing?

If it works on your dev box but not on your production server, that typically means it's a routing issue or a firewall issue.

Related

Unable to authenticate to http API when using public url from same machine (Kestrel/.NET7)

I have a .NET7 service which is running kestrel to host an http API (REST controller). The service uses windows authentication with a local windows account. There is an SSL certificate installed and the service is running on a Windows VM in Azure.
When I access the service using a browser or httpClient from my home PC everything works great. e.g. https://blah.myservice.com:21000/api/foo - this challenges me for credentials, I put them in and it returns data and the browser is happy with the SSL cert.
When I access the service in the same way from another Azure VM on the same network it also works as expected.
The issue is that when I access the public URL from the same machine that the service is running on I get a 401 unauthorized response from the service.
If I do https://localhost:21000/api/foo then it challenges me for credentials and returns data just fine, but the browser is not happy with the SSL cert because the domain in the browser does not match. That's not a mystery, obviously. But the service does work. It also works using the local network IP address of the machine.
I don't understand why I get a 401 when using the public URL - it's hitting the right service because I can see the request come in through the log files, it just won't authenticate after challenging me.
The reason this bothers me is that I have a number of services running on a few VMs - sometimes they take data from each other which means they have to effectively connect to localhost to call the REST controllers on another service. This will fail with a 401 if I use the public URL, but will also fail if I use "localhost" because the certificate does not validate. e.g. this code fails when going from one service to another on the same host (or just running it as a console app on the same server):
var credentials = new NetworkCredential("username", "password");
var httpClientHandler = new SocketsHttpHandler { Credentials = credentials };
HttpClient httpClient = new HttpClient(httpClientHandler, true);
try
{
string result = await httpClient.GetStringAsync("https://blah.myservice.com:21000/api/foo");
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
string result = await httpClient.GetStringAsync("https://localhost:21000/api/foo");
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Both of the above requests fail - I realise I can set the RemoteCertificateValidationCallback to always return true but that's a hack and I have a valid SSL cert so it makes no sense to do that.
Is anyone able to explain why this doesn't work and how to fix it?

Unable to use *.pfx certificate with kestrel inside windows service

I'm trying to configure my ASP.Net Core 3.1 app using windows service and kestrel.
So far the app works and starts correctly. Also works correctly in console mode.
However when i add https with my certificate (*.pfx container) things get weird.
The app works in console made without troubles but fails in service mode with exception:
System.InvalidOperationException: Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date.
To generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'.
For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054.
at Microsoft.AspNetCore.Hosting.ListenOptionsHttpsExtensions.UseHttps(ListenOptions listenOptions, Action`1 configureOptions)
at Microsoft.AspNetCore.Hosting.ListenOptionsHttpsExtensions.UseHttps(ListenOptions listenOptions)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IServerAddressesFeature addresses, KestrelServerOptions serverOptions, ILogger logger, Func`2 createBinding)
at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
Service mode is configured using Microsoft.Extensions.Hosting.WindowsServices. Everything is configured using ConfigureWebHostDefaults() without any specifics regarding certificates or anything. And here is a snippet from appsettings.json:
"Urls": "https://*",
"Kestrel": {
"Certificates": {
"Default": {
"Path": "full_path_to_my_certificate_container.pfx",
"Password": "password"
}
}
}
Works flawlessly in console mode, certificate is applied correctly, app is accessible. Service mode is used without any configuration changes. Even environment is the same (actually it's not even set, so it's a kind of "production").
Tried switching service account to my admin account. No difference at all.
What am i missing?
UPDATE_01:
I've changed my config from "*.pfx" certificate to store:
{
"Kestrel": {
"Certificates": {
"Default": {
"Location": "LocalMachine",
"Store": "Root",
"Subject": "MyCertSubjectName"
}
}
}
}
As before this works perfectly in console mode but not in service mode giving the same exception.
UPDATE_02:
Tried the full "Endpoints" block from this link:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-3.1#listenoptionsusehttps
No difference at all. I can see that my config is used correctly because tested it with incorrect values and the app reported them in logs.
UPDATE_03:
Played around with permissions for my certificate in the store. No luck.
I'm lost...
I feel ashamed...
Seems that in service mode my config wasn't read. I was testing this fact only in console mode (it was easier) and thought it works perfectly in service mode so that is why i excluded this part.
When moving it to appsettings.json everything started working just fine.
Sorry if anyone is typing the comments to this topic right now...

Not able to connect from Windows Application to IdentityServer4 with SSL

I have a Windows application that is using the "password" grant type. It is able to authenticate to the Identityserver4 without SSL, but not with SSL. The problem is that it is giving an error:
The underlying connection was closed: An unexpected error occurred on a send
I tried it from postman, and it worked, but not from my Windows Application. Below is the code:
var tokenClient = new TokenClient($"{IdentityServer}/connect/token", Constants.ClientId, Constants.ClientSecret);
var tokenResponseTask = tokenClient.RequestResourceOwnerPasswordAsync(username, password, Constants.Scope);
tokenResponseTask.Wait();
return tokenResponseTask.Result;
Below also is another code the I tried, but it doesn't work:
TokenResponse tokenResponse;
string request = $"client_id={clientId}&client_secret={clientSecret}&grant_type={grantType}&scope={scope}&username={username}&password={password}";
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
byte[] result = client.UploadData(endpointUrl, "POST", Encoding.UTF8.GetBytes(request));
string resultJson = Encoding.UTF8.GetString(result, 0, result.Length);
tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(resultJson);
}
Finally, I was able to find the solution under the following link:
Authentication failed because remote party has closed the transport stream
'The underlying connection was closed' error is often seen when the SSL handshake fails.
SSL handshake failure usually has something to do with the relevant SSL certificate and whether or not the certificate is trusted.
Check ...
Whether IdentityServer is configured to run under HTTP and HTTPS.
Your Windows Application is correctly configured for SSL.
Test some of the IdentityServer endpoints using a browser with the https protocol.
Hope this gets you going on a helpful investigation path.

401 Unauthorized while ExchangeService.SubscribeToPushNotifications

Hi I have written an standalone Windows Forms application which uses EWS (Exchange Web Services) Managed API to listen to the new mail event on a particular email id. I am using impersonation. This is a part of my code:
service = new ExchangeService(SyncSettings.ExchangeServerVersion);
service.Credentials = new WebCredentials(userid, password);
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, impersonatedUserId);
service.Url = new Uri(exchnguri);
FolderId[] folders=new FolderId[1];
folders[0] = new FolderId(WellKnownFolderName.Inbox);
EventType[] events = new EventType[1];
events[0] = EventType.NewMail;
subscription = service.SubscribeToPushNotifications(folders, new Uri(listenUri), notificationInterval, "", events);
On Exchange Server side, I have provided one user account privileges to impersonate another user account.
When I run app in one environment it works fine. But when I run it in another it gives following error:
Immediate Stack Trace
===================================================================================
Microsoft.Exchange.WebServices.Data.ServiceRequestException : The request failed. The remote server returned an error: (401) Unauthorized.
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request)
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ValidateAndEmitRequest(IEwsHttpWebRequest& request)
at Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.Execute()
at Microsoft.Exchange.WebServices.Data.ExchangeService.SubscribeToPushNotifications(IEnumerable`1 folderIds, Uri url, Int32 frequency, String watermark, EventType[] eventTypes)
at com.org.app.Class.startListeningPushNotifications(String listenUri, Int32 notificationInterval) in c:\SW\app\Class.cs:line 156
Inner Exception 1 : Stack Trace
-----------------------------------------------------------------------------
System.Net.WebException . The remote server returned an error: (401) Unauthorized.
at System.Net.HttpWebRequest.GetResponse()
at Microsoft.Exchange.WebServices.Data.EwsHttpWebRequest.Microsoft.Exchange.WebServices.Data.IEwsHttpWebRequest.GetResponse()
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request)
The only difference I observe in two environments is:
In first environment I login owa (Outlook Web Access) using domainx\userx, and to send mail to self account (that is, to the account with which I have logged in) I put userx#domainx.com in to field
However in second environment I login owa using domainxdc\userx (notice 'dc' in domainxdc), and send self mail with userx#domainx.com in to field. (notice no 'dc' in domainx.com)
I dont think that is giving me 401 Unauthorised, since I can login to owa using both impersonating and impersonated account. And I have given impersonating privileges in 2nd environment in exactly the same way as in 1st environment.
So why I am getting 401 Unauthorised ?
We are using Exchange Server 2007 and Windows Server 2008 SP2.
Here's something to try--might work:
service.CookieContainer = new CookieContainer();
I'm not very clear on why this helps, and in my case, it was going against Exchange Online, not your on-prem E2007. Might help; can't hurt. There was a blog post on this, but not sure if this will apply to your case.

System.Net.WebException: The request failed with HTTP status 401: Unauthorized

Ok, so I have this .NET 1.1 application (written by someone way back) which is like a document repository and it worked fine in the past. I suddenly get this error when trying to search for items/documents:
Page: /CPDEPforIT/SearchResults.aspx
Error:
System.Net.WebException: The request failed with HTTP status 401:
Unauthorized. at
System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage
message, WebResponse response, Stream responseStream, Boolean
asyncCall) at
System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String
methodName, Object[] parameters) at
CPDEPforIT.InktomiSearchService.soapSearchService.getSearchResults(SearchInput
in0) at CPDEPforIT.SearchResults.GetDatasetForSearchQuery(SearchInput
searchInput) at CPDEPforIT.SearchResults.Page_Load(Object sender,
EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at
System.Web.UI.Control.LoadRecursive() at
System.Web.UI.Page.ProcessRequestMain()
I don't remember any changes. Could this have been caused by something external to the application (IIS configurations/permissions, Server, Database)?
There are several things you need to verify.
Does the web service you are trying to access allow Anonymous Access? Authentication can be tricky for web-to-web calls
What is the web application running under, IWAM_xxx or IUSR_xxx? Or are you using an application pool running under a specific identity?
You may want to make sure your web application server's ASPNET or NETWORK SERVICE accounts can access your web service server.
If you want to get it working you could just provide an account for Anonymous Access...
Thanks!
I have also faced this type of issue before. In my case permission to the code folder works. Please check the folder permissions and then try with the IIS permissions.