Send email from a .Net Framework Winforms application and service using Microsoft accounts.

Fortecho Solutions Ltd 0 Reputation points
2024-06-28T11:56:45.4266667+00:00

Hello.

We provide a .Net Framework Winforms application with a service. Both share code which allows our customers to send email from their own email accounts, currently using MailKit, although we could use another client if necessary.

Where they want to use Microsoft accounts, will they be able to continue to use their username and password? If they choose to use OAuth instead, how would we implement this so that the Winforms application can be configured once, sends mail, and the service can also pick up those credentials? Is that possible? I've tried to follow both Microsoft and MailKit's documentation on MSAL, but it's not clear to me which approach to implement.

Many thanks

Jon

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,869 questions
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,609 questions
Microsoft Entra
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Jiale Xue - MSFT 42,411 Reputation points Microsoft Vendor
    2024-06-28T13:20:52.02+00:00

    Hi @Fortecho Solutions Ltd , Welcome to Microsoft Q&A,

    To send emails from a Microsoft account from a WinForms application or service, you can choose to use OAuth2 for authentication. OAuth2 is more secure than traditional usernames and passwords.

    In the service, read the stored token and use it to authenticate and send emails:

    public class EmailService
    {
        private static readonly string tokenCachePath = "token_cache.json";
    
        public async Task SendEmailAsync(string to, string subject, string body)
        {
            var token = File.ReadAllText(tokenCachePath);
    
            var message = new MimeMessage();
            message.From.Add(new MailboxAddress("Your Name", "your-email@example.com"));
            message.To.Add(new MailboxAddress("", to));
            message.Subject = subject;
            message.Body = new TextPart("plain")
            {
                Text = body
            };
    
            using var client = new SmtpClient();
            await client.ConnectAsync("smtp.office365.com", 587, MailKit.Security.SecureSocketOptions.StartTls);
            await client.AuthenticateAsync("your-email@example.com", token);
            await client.SendAsync(message);
            await client.DisconnectAsync(true);
        }
    }
    
    

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. Raja Pothuraju 1,600 Reputation points Microsoft Vendor
    2024-07-03T16:53:13.49+00:00

    Hello @Fortecho Solutions Ltd,

    Thank you for your response.

    I understand that after adding the line Net.ServicePointManager.SecurityProtocol = Net.SecurityProtocolType.Tls12 to your code, the error "HttpRequestException: SocketException: An existing connection was forcibly closed by the remote host" was resolved. I appreciate the update on this matter.

    Regarding the Entra app registration, I see that you have registered the application with the supported account types set to "Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts (e.g., Skype, Xbox)." This means your application can be used by all users with a work or school account, as well as personal Microsoft accounts. But users are getting an error AADSTS50020 when they login with Hotmail account.

    To address the issue you're experiencing, please refer to the following Microsoft documentation and review the suggested solutions:

    Error Code AADSTS50020 - User account identity provider does not exist

    Based on your user behavior, it appears that your scenario falls under Cause 3 as documented. Your current code looks like this:

    
    var app = ConfidentialClientApplicationBuilder.Create(clientId)
    
                .WithClientSecret(clientSecret)
    
                .WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}"))
    
                .Build();
    
    

    If you are targeting the /tenantID endpoint, encountering this error message is expected. Instead, you should use the https://login.microsoftonline.com/common endpoint.

    Please update your code accordingly:

    
    var app = ConfidentialClientApplicationBuilder.Create(clientId)
    
                .WithClientSecret(clientSecret)
    
                .WithAuthority(new Uri("https://login.microsoftonline.com/common"))
    
                .Build();
    
    

    This change should help resolve the issue.

    If the issue persists, I recommend that you review the other causes mentioned in the document linked above and let us know the update.

    I hope this information is helpful. Please feel free to reach out if you have any further questions.


    Please "Accept the answer" if the information helped you. This will help us and others in the community as well.

    Thanks,
    Raja Pothuraju.