I need to make a VB .net tool to read email and save attachments. My company recently migrated from on-premise Exchange to Office 365. I have been reading EWS tutorials for 2 days now, and searching StackOverflow, but cannot get past the most basic step of authorized access to the O365 mailbox.
I took the original code from this article: htp://www.c-sharpcorner.com/UploadFile/jj12345678910/reading-email-and-attachment-from-microsoft-exchange-server/. I had some trouble converting it to VB using the Telerik converter but I think I have it right. Each time I try using the FindItemsResults method it halts with "(401) Unauthorized."
The instructions for asking a question state that I should include links to what I have already found and why it did not work, but my SO reputation only allows me 2 links. Here is what I have tried:
I have tried every possible usercode and domain combination I can think after reading this page: htps://stackoverflow.com/questions/10107872/ews-connections-issues-401-unauthorized
I am trying to read my own mailbox, so this one does not help: htps://stackoverflow.com/questions/43346498/401-unauthorized-access-when-using-ews-to-connect-to-mailbox
My connection looks identical to the connection on this page, but using it in my project did not get past the same Unauthorized error as before:htps://stackoverflow.com/questions/29009295/ews-managed-api-retrieving-e-mails-from-office365-exchange-server
Here is my code:
Public Class Form1
Public Exchange As ExchangeService
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lstMsg.Clear()
lstMsg.View = View.Details
lstMsg.Columns.Add("Date", 150)
lstMsg.Columns.Add("From", 250)
lstMsg.Columns.Add("Subject", 400)
lstMsg.Columns.Add("Has Attachment", 50)
lstMsg.Columns.Add("Id", 100)
lstMsg.FullRowSelect = True
End Sub
Public Sub ConnectToExchangeServer()
Me.lblMsg.Text = "Connecting to Exchange Server"
lblMsg.Refresh()
Try
'Exchange = New ExchangeService(ExchangeVersion.Exchange2013)
Exchange = New ExchangeService()
Exchange.TraceEnabled = True
'Exchange.UseDefaultCredentials = True
Exchange.Credentials = New WebCredentials("DoeJohn", "mypasswd", "mycorp.com")
'Exchange.AutodiscoverUrl("DoeJohn@mycorp.mail.onmicrosoft.com", AddressOf MyRedirectionURLValidationCallback)
'Exchange.AutodiscoverUrl("John.Doe@mycorp.com", AddressOf MyRedirectionURLValidationCallback)
Exchange.Url = New System.Uri("https://outlook.office365.com/ews/exchange.asmx")
lblMsg.Text = "Connected to Exchange Server"
lblMsg.Refresh()
Catch ex As Exception
MsgBox("Fatal Error in Connect: " & ex.Message)
End
End Try
End Sub
Public Function MyRedirectionURLValidationCallback(RedirectionURL As String) As Boolean
Dim Result As Boolean = False
Dim RedirectionURI As Uri = New Uri(RedirectionURL)
If RedirectionURI.Scheme = "https" Then
Return True
End If
Return False
End Function
Private Sub btnRead_Click(sender As Object, e As EventArgs) Handles btnRead.Click
Call ConnectToExchangeServer()
Dim ts As TimeSpan = New TimeSpan(0, -1, 0, 0)
Dim MyDate As DateTime = DateTime.Now.Add(ts)
Dim MyFilter As SearchFilter.IsGreaterThanOrEqualTo = New SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, MyDate)
If Exchange IsNot Nothing Then
Dim FindResults As FindItemsResults(Of Item) =
Exchange.FindItems(WellKnownFolderName.Inbox, MyFilter, New ItemView(50))
Dim NewRow As ListViewItem
For Each MyItem As Item In FindResults
Dim Message As EmailMessage = EmailMessage.Bind(Exchange, MyItem.Id)
NewRow = New ListViewItem(Message.DateTimeReceived.ToString())
NewRow.SubItems.Add(Message.From.Name.ToString())
NewRow.SubItems.Add(Message.Subject)
NewRow.SubItems.Add(Message.HasAttachments.ToString())
NewRow.SubItems.Add(Message.Id.ToString())
lstMsg.Items.Add(NewRow)
Next
Else
End If
End Sub
I have confirmed that AutoDiscover is correctly finding the server, comparing to Test Email AutoConfiguration in Outlook.
An interesting sidenote -- after my company moved to Office 365, I noticed that I have two new SMTP mail addresses. If I open Outlook properties on myself, I see this:
This means someone can send mail to me now either at the old address john.doe@mycorp.com, and also now at doejohn@mycorp.mail.onmicrosoft.com. The new address is based on my domain usercode. I tested the microsoft one from a gmail account and it works.
To sum up, here are my questions: 1. Why am I getting the (401) Unauthorized errors when I try to read my Inbox? 2. Does Office 365 expect me to use my domain account or my mailbox name for user credentials? 3. In the domain part of the WebCredentials statement, do I use my company's mycorp.com or instead do I use Office 365's domain outlook.office365.com?
If you have read this far, many thanks!
I found the answer to the problem above, so I'll share here in case anyone needs it. The problem is down to security protocols added by my IT organization that were not documented because of recent phishing attacks on our company.
The first clue was that IT stated if I want to check company email on my personal 4G device like smartphone or ipad, I must also install Microsoft InTune for MFA connection to the O365 mail server. Since I am unaware of how to integrate InTune into my .Net app, I had to look for another answer.
I requested and was approved to move my functional mailbox from O365 to an on-premise Exchange server for this app. That solved the authentication problem.