Just started a new WPF project that needs to connect to 365 for SMPT and IMAP.
I have obtained the following from Entra ClientID TenantID SecretValue SecretID
But I'm struggling to put it all together, so started with basic authentication first...
Public Function SendMail(MailBody As String, MailSubject As String, SendTo As String, SentFrom As String) As String
Try
Dim vEmail = New MimeMessage()
vEmail.From.Add(MailboxAddress.Parse(SentFrom))
vEmail.To.Add(MailboxAddress.Parse(SendTo))
vEmail.Subject = MailSubject
vEmail.Body = New TextPart(TextFormat.Html) With {.Text = MailBody}
Using vClient = New SmtpClient
vClient.Connect("smtp-legacy.office365.com", 587, SecureSocketOptions.StartTls)
vClient.Authenticate(MailUserName, MailPasssword)
vClient.Send(vEmail)
vClient.Disconnect(True)
End Using
Return "Email was sent!"
Catch ex As Exception
EmailError(ex)
Return "Email sending failed"
End Try
End Function
and that works.
Tried this based on an example at the MailKit site...
Public Function SendAuthMail(MailBody As String, Mailsubject As String, SendTo As String, SentFrom As String) As String
Try
Dim vEmail = New MimeMessage()
vEmail.From.Add(MailboxAddress.Parse(SentFrom))
vEmail.To.Add(MailboxAddress.Parse(SendTo))
vEmail.Subject = Mailsubject
vEmail.Body = New TextPart(TextFormat.Html) With {.Text = MailBody}
Dim options = New PublicClientApplicationOptions With {.ClientId = vClientID,
.TenantId = vTenantID,
.RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"}
Dim scopes = New String() {"email", "offline_access", "https://outlook.office.com/SMTP.Send"}
Dim publicClientApplication = PublicClientApplicationBuilder.CreateWithApplicationOptions(options).Build()
Dim authToken = publicClientApplication.AcquireTokenInteractive(scopes).ExecuteAsync()
Dim v2 = New SaslMechanismOAuth2(authToken.Account.Username, authToken.AccessToken)
Using vClient = New SmtpClient
vClient.Connect("smtp.office365.com", 587, SecureSocketOptions.StartTls)
vClient.Authenticate(v2)
vClient.Send(vEmail)
vClient.Disconnect(True)
End Using
Return "Email was sent"
Catch ex As Exception
EmailError(ex)
Return "Email sending failed"
End Try
End Function
But authToken.Account.Username and authtoken.AccessToken both fail with 'Account' is not a member of 'Task(Of AuthenticationResult)' and 'AccessToken' is not a member of 'Task(Of AuthenticationResult)
Any pointers would be appreciated - the desk is proving to be much harder than my head!
============= EDIT ===========
Using...
Dim AuthClient = ConfidentialClientApplicationBuilder.Create(vClientID).
WithAuthority(AzureCloudInstance.AzurePublic, vTenantID).
WithClientSecret(SecretValue).
Build
Dim AuthResult = AuthClient.AcquireTokenForClient({"https://outlook.office365.com/.default"}).ExecuteAsync.Result Dim vAuth As New SaslMechanismOAuth2(SentFrom, AuthResult.AccessToken)
I can now get to 'authentication failed' - but it doesn't really give me a clue as to why.
==================Further edit=================
The main problem seems to be authentication - and it would appear to to be down to SaslMechanismOuth2 and Authtoken
It should (according to all the examples I have seen) expose .Account.UserName and .AccessToken - but they are not available.
If you look through the connection dialogue here, you can see that the server just drops the connection with starttls, but connects with ssl. However, you can see that AUTHENTICATE XOAUTH2 fails to authenticate. There should be a long string.
Connected to imap://outlook.office365.com:993/?starttls=always
Connected to imap://outlook.office365.com:993/?starttls=always
Connected to imap://outlook.office365.com:993/?starttls=always
Connected to imaps://outlook.office365.com:993/
S: * OK The Microsoft Exchange IMAP4 service is ready. [TABPADQAUAAxADIAMwBDAEEAMAAxADAAMgAuAEcAQgBSAFAAMQAyADMALgBQAFIATwBEAC4ATwBVAFQATABPAE8ASwAuAEMATwBNAA==]
C: A00000000 CAPABILITY
S: * CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
S: A00000000 OK CAPABILITY completed.
C: A00000001 AUTHENTICATE XOAUTH2 ********
S: A00000001 NO AUTHENTICATE failed.
It's now working - and there were a couple of factors if you rely on the MailKit documentation here
Firstly scopes - this should be just
Dim scopes = New String() {"https://outlook.office365.com/.default"}
Secondly, you must use result for authToken and add the email user name as text...
Dim authToken = vAppBuilder.AcquireTokenForClient(scopes).ExecuteAsync()
vResult = authToken.Result
vToken = vResult.AccessToken
Dim vText = authToken.result.ToString
Dim vT2 = New SaslMechanismOAuth2(MailUserName, vToken)
Putting the entire thing together
Private Async Sub ReturnIMAP()
Dim vImage As New LoadingImage
Try
LoadingStarted("Running IMAP... Please wait...", vImage)
Dim vT2Text As String = ""
Dim vResult = Nothing
Dim vToken = Nothing
Dim vNumber As Integer = 0
' Dim vT3 = Nothing
' Dim vT4 As String = ""
Dim vMessage As String = ""
Await Task.Run(Sub()
Dim vAppBuilder = ConfidentialClientApplicationBuilder.Create(vClientID).WithClientSecret(SecretValue).WithTenantId(vTenantID).WithAuthority(RedirectUri).Build()
Dim scopes = New String() {"https://outlook.office365.com/.default"}
Dim authToken = vAppBuilder.AcquireTokenForClient(scopes).ExecuteAsync()
vResult = authToken.Result
vToken = vResult.AccessToken
Dim vText = authToken.result.ToString
Dim vT2 = New SaslMechanismOAuth2(MailUserName, vToken)
Using vClient As New ImapClient(New ProtocolLogger("C:\Temp\imap3.log"))
vClient.Connect("outlook.office365.com", 993, SecureSocketOptions.SslOnConnect)
vClient.Authenticate(vT2)
vClient.Inbox.Open(FolderAccess.ReadWrite)
vNumber = vClient.Inbox.Count
If vNumber > 0 Then
Using wr As New StreamWriter("C:\Temp\EmailMessages.txt", True)
vClient.Inbox.Open(FolderAccess.ReadOnly)
Dim UIDS = vClient.Inbox.Search(SearchQuery.All)
For i As Integer = 0 To UIDS.Count - 1
Dim Message = vClient.Inbox.GetMessage(i)
Message.WriteTo(String.Format("{0}.eml", i))
vMessage = Message.ToString
wr.WriteLine(vMessage)
Next
End Using
End If
vClient.Disconnect(True)
End Using
End Sub)
LoadingCompleted("Ready", "Inbox unread messages = " & vNumber, vImage)
Catch ex As Exception
EmailError(ex)
LoadingCompleted("Error", "Error", vImage)
End Try
End Sub