I am trying to find the unique id of a folder in Outlook.
For some reason I keep getting an error with the AutoDiscoverUrl method, but I have no idea why. I have tried all the possible solutions on StackOverflow.
I am trying to run it in a commandline program using C#, and have commented/documented the code. I have used others' example on how to do this, but it doesn't work.
static void Main(string[] args)
{
// Set server binding
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.UseDefaultCredentials = true;
// Set Credentials
service.Credentials = new WebCredentials("xxxx", "xxxxx", "xxxx");
service.UseDefaultCredentials = true;
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
// Set the URL
service.AutodiscoverUrl("xxxx", Callback);
// Error Tracing
service.TraceEnabled = true;
// Redirect callback
// Set View
FolderView view = new FolderView(100);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.Root, view);
// Find specific folder
foreach (Folder f in findFolderResults)
{
// Show FolderId of the folder "test"
if (f.DisplayName == "test")
{
Console.WriteLine(f.Id);
}
}
}
private static bool Callback(string redirectionUrl)
{
bool result = false;
var redirectionUri = new Uri(redirectionUrl);
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
You could find the unique id of the folder using the below code:
ExchangeService Service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
Service.UseDefaultCredentials = false;
Service.Credentials = new WebCredentials("yourUserID", "yourPassword");
Mailbox ProdSupportMailbox = new Mailbox("ProdSupport#company.com");
Service.AutodiscoverUrl("ProdSupport#company.com");
FolderView view = new FolderView(100);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
FindFoldersResults findFolderResults = server.FindFolders(WellKnownFolderName.Root, view);
// find specific folder
foreach(Folder f in findFolderResults)
{
// show folderId of the folder "Test"
if (f.DisplayName == "Test")
{
Console.WriteLine(f.Id);
}
}
For more information, please refer to these links:
Exchange Web Service FolderId for a not well known folder name
Microsoft Exchange Web Services reading my local Outlook folders INSTEAD of another address
Related
I want to fetch the details from my outlook mailbox but don't have the Microsoft exchange server. I only have cloud-based services.
I tried to use the below-given code but that is an exchange server API solution. The second method is to open the outlook app and then accessing the mailbox but doesn't want this solution.
try
{
'Mailbox credentials'
string emailAddress = AppSettings.Office365EmailAddress;
string password = AppSettings.Office365Password;
ServicePointManager.ServerCertificateValidationCallback =
CertificateValidationCallBack;
ExchangeService service = new
ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.Credentials = new WebCredentials(emailAddress, password);
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
service.PreAuthenticate = true;
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress,
emailAddress);
ItemView view = new ItemView(int.MaxValue);
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox,
SetFilter(), view);
DataTable dtEmails = GenerateEmailDataTable();
DataRow dr = dtEmails.NewRow();
foreach (Item item in findResults.Items)
{
if (item.Subject != null)
{
Match match = Regex.Match(item.Subject.ToString(), regJMSNumber);
if (match != null)
{
dr["EmailTo"] = item.DisplayTo.ToString();
dr["EmailFrom"] = item.DisplayTo.ToString();
dr["EmailCC"] = item.DisplayCc.ToString();
dr["EmailBCC"] = item.DisplayTo.ToString();
dr["EmailSubject"] = item.Subject.ToString();
dr["EmailBody"] = item.Body.ToString();
dr["CreatedOn"] = item.Subject.ToString();
dr["IsActive"] = true;
}
else
{
Console.WriteLine("Subject Not Match");
}
}
}
}
'Error handler.'
catch (System.Exception e)
{
Console.WriteLine("{0} Exception caught: ", e);
}
finally
{
}
Another approach is the Power Automate option but I want to do it programmatically.
Used https://outlook.office365.com/EWS/Exchange.asmx API.
When I am using EWS (exchange API), the application throwing a 401 Unauthorised requests failed exception.
Please tell me any other way to track the outlook emails with all details like EmailTo, EmailSent, EmailSubject, EmailBody, EmailCC, EmailBCC, and all the trailing messages.
I have developed an engine to automatically process the emails sent to a particular mailbox using EWS (Exchange Web Services) Push Subscription. Everything is working fine except, I need to set the follow-up flag text with some custom message like we do in outlook (screen-shots below):
Custom text:
Sample email after setting the flag text:
I am using below code to do that, however the text is not displayed on email, only dates are reflecting with below code:
public bool MoveToFolder(EmailMessage mail, string folderName, bool MarkForFollowUp, string FollowUpText)
{
try
{
var folderView = new FolderView(100);
if (MarkForFollowUp)
{
try
{
ExtendedPropertyDefinition followUpTextFlag = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "ChangeDetails", MapiPropertyType.String);
Flag flag = new Flag();
flag.FlagStatus = ItemFlagStatus.Flagged;
flag.StartDate = DateTime.Now;
flag.DueDate = DateTime.Now.AddHours(1);
mail.Flag = flag;
workLog.WriteVerbose($"Setting flag with followup-text: {FollowUpText}", "Notify.cs > MoveToFolder()");
mail.SetExtendedProperty(followUpTextFlag, FollowUpText);
mail.Update(ConflictResolutionMode.AutoResolve);
workLog.WriteVerbose($"Message follow-up flag set successfully.", "Notify.cs > MoveToFolder()");
}
catch (Exception ex)
{
// Ignore error while settings the flag
workLog.WriteVerbose($"Error occurred while setting the follow-up flag. Reason: {ex.Message}", "Notify.cs > MoveToFolder()");
}
}
folderView.PropertySet = new PropertySet(BasePropertySet.IdOnly);
folderView.PropertySet.Add(FolderSchema.DisplayName);
folderView.Traversal = FolderTraversal.Deep;
FindFoldersResults findFolderResults = _service.FindFolders(WellKnownFolderName.Root, folderView);
if (findFolderResults == default(FindFoldersResults))
{
return false;
}
try
{
FolderId folderId = findFolderResults.Cast<Folder>().FirstOrDefault(Folder => Folder.DisplayName == folderName).Id;
mail.Move(folderId);
return true;
}
catch
{
return false;
}
}
catch (Exception)
{
return false;
}
}
You need to set the PidLidFlagRequest extended property https://learn.microsoft.com/en-us/office/client-developer/outlook/mapi/pidlidflagrequest-canonical-property with the text you want to show eg
ExtendedPropertyDefinition followUpTextFlag = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "ChangeDetails", MapiPropertyType.String);
ExtendedPropertyDefinition PidLidFlagRequest = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Common, 0x8530, MapiPropertyType.String);
ExtendedPropertyDefinition PidLidFlagString = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Common, 0x85C0, MapiPropertyType.Integer);
Flag flag = new Flag();
flag.FlagStatus = ItemFlagStatus.Flagged;
flag.StartDate = DateTime.Now;
flag.DueDate = DateTime.Now.AddHours(1);
mail.Flag = flag;
mail.SetExtendedProperty(PidLidFlagRequest, "PidFlag Blah Blah");
mail.SetExtendedProperty(PidLidFlagString, 0);
mail.SetExtendedProperty(followUpTextFlag, "Blah Balh");
mail.Update(ConflictResolutionMode.AutoResolve);
I am trying to find the unique ID of a subfolder of the Inbox folder of a shared mail, named "Processed". When using WellKnownFolderName.Root and a deep traversal, I find alot of different folders. But using the WellKnownFolderName.Inbox shows me 0 folders, as if there is 0 subfolders of the Inbox folder, which is not true.
ExchangeService Service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
Service.UseDefaultCredentials = false;
Service.Credentials = new WebCredentials("xxxx", "xxxx");
Mailbox ProdSupportMailbox = new Mailbox("xxxx");
Service.AutodiscoverUrl("xxxx");
FolderView view = new FolderView(100);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
view.PropertySet.Add(FolderSchema.DisplayName);
view.Traversal = FolderTraversal.Deep;
FindFoldersResults findFolderResults = Service.FindFolders(WellKnownFolderName.Inbox, view);
// Find specific folder
foreach(Folder f in findFolderResults)
{
if (f.DisplayName == "Processed")
Console.WriteLine(f.Id);
// etc
I want to select the user "test" so I can create a contact into his mailbox.
My actual problem is that it will create Contacts into my user "c-sharp".
"c-sharp" has full access on "test" mailbox
I changed the IP and the contact infos users are also only for testing.
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.EnableScpLookup = false;
service.Credentials = new WebCredentials("c-sharp", "c-sharp", "domain");
service.UseDefaultCredentials = false;
IgnoreBadCertificates();
service.Url = new Uri("https://192.000.000.000/EWS/Exchange.asmx");
Contact contact = new Contact(service);
// Specify the name and how the contact should be filed.
contact.GivenName = "n.a.";
contact.FileAsMapping = FileAsMapping.SurnameCommaGivenName;
contact.DisplayName = "bau gmbh";
// Specify the company name.
contact.CompanyName = "bau";
// Specify the business, home, and car phone numbers.
contact.PhoneNumbers[PhoneNumberKey.BusinessPhone] = "00000 00000";
contact.PhoneNumbers[PhoneNumberKey.MobilePhone] = "n.a.";
contact.PhoneNumbers[PhoneNumberKey.BusinessFax] = "00000 00000";
// Specify two email addresses.
contact.EmailAddresses[EmailAddressKey.EmailAddress1] = new EmailAddress("e#mail.de");
//homepage
contact.BusinessHomePage = "n.a.";
// Specify the home address.
PhysicalAddressEntry paEntry1 = new PhysicalAddressEntry();
paEntry1.Street = "straße";
paEntry1.City = "stadt";
paEntry1.State = "D";
paEntry1.PostalCode = "88890";
paEntry1.CountryOrRegion = "Deutschland";
contact.PhysicalAddresses[PhysicalAddressKey.Home] = paEntry1;
contact.Save();
Already tried this:
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.PrincipalName, "test");
I tested it with "test" and "test#domain" and "test#domain.de"
And get back this error:
"Der Name des Identitätsprinzipals ist ungültig."
Own translation: "The name of the identity principal is unvailed"
You can use Impersonation like this
ExchangeUserData exchangeUserData = new ExchangeUserData();
exchangeUserData.Username = "c-sharp";
exchangeUserData.Password = "c-sharp"; // c-sharp's Password
ExchangeService service = Service.ConnectToServiceWithImpersonation(exchangeUserData, impersonatedUserPrincipal);
Contact contact = new Contact(service);
// Specify the name and how the contact should be filed.
contact.GivenName = "n.a.";
contact.FileAsMapping = FileAsMapping.SurnameCommaGivenName;
contact.DisplayName = "bau gmbh";
// Specify the company name.
contact.CompanyName = "bau";
// Specify the business, home, and car phone numbers.
contact.PhoneNumbers[PhoneNumberKey.BusinessPhone] = "00000 00000";
contact.PhoneNumbers[PhoneNumberKey.MobilePhone] = "n.a.";
contact.PhoneNumbers[PhoneNumberKey.BusinessFax] = "00000 00000";
// Specify two email addresses.
contact.EmailAddresses[EmailAddressKey.EmailAddress1] = new EmailAddress("e#mail.de");
//homepage
contact.BusinessHomePage = "n.a.";
// Specify the home address.
PhysicalAddressEntry paEntry1 = new PhysicalAddressEntry();
paEntry1.Street = "straße";
paEntry1.City = "stadt";
paEntry1.State = "D";
paEntry1.PostalCode = "88890";
paEntry1.CountryOrRegion = "Deutschland";
contact.PhysicalAddresses[PhysicalAddressKey.Home] = paEntry1;
contact.Save();
If your c-sharp user has the proper rights in Exchange, you should be able to do:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = new WebCredentials("c-sharp", "c-sharp", "domain");
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.PrincipalName, "test");
If this doesn't work for you, please comment below or update your question (there's an "edit" link under it) with the exact behavior you are seeing including any error messages.
Problem sloved.
I found the bug... both of you are right just change:
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.PrincipalName, "test");
Into:
service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "test#domain.de");
Thats all ...
Great thanks to you
With reference to my previous question, I already wrote my program and it is working awesome when I am using VS2008 for run it.
I have two more questions:
1. I want to check with you guys when I run my program all the mail are appearing in VS output as xml file, but I never used to print them in output. is it usual for all or I need to add something to remove it. I feel it takes long time from my PC to show mails in output.
2. my second question is that when I want to use only exe file stand alone(run program via exe file not with VS ) I am receiving below error and program is hanging & close.
"MailReader has encountered a problem and needs to close. We are
sorry for the inconvenience."
As I mentioned above this program is working fine in VS.
I copy part of my code that read mails and split them for your reference.
public void ReadMail()
{
ServicePointManager.ServerCertificateValidationCallback += delegate(object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors) { return true; };
try
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.TraceEnabled = true;
service.Credentials = new WebCredentials(_username, _password); //Modify this
service.Url = new Uri(_exchange); //Modify this
service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Url = new Uri(_exchange);
service.TraceEnabled = true;
service.Credentials = new WebCredentials(_username, _password); //Modify this
service.Url = new Uri(_exchange);
//SearchFilter to get unreaded messages only.
SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
ItemView itemview = new ItemView(Int16.MaxValue);
//DateTime searchdate = new DateTime(2012, 7, 6); //Year, month, day
SearchFilter greaterthanfilter = new SearchFilter.IsGreaterThan(ItemSchema.DateTimeSent, Convert.ToDateTime(startDate));
SearchFilter lessthanfilter = new SearchFilter.IsLessThan(ItemSchema.DateTimeSent,Convert.ToDateTime(finishDate));
SearchFilter[] f = { greaterthanfilter, lessthanfilter };
SearchFilter filter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, f);
//Folder folder = Folder.Bind(this.m_Service, WellKnownFolderName.MsgFolderRoot); //Or the folder you want to search in
//FindItemsResults<Item> results = folder.FindItems(filter, new ItemView(1000));
FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.SentItems,filter, itemview);
Action action = () => fr.setText(findResults.Items.Count + "mails need to analysis from "+startDate +" to "+ finishDate);
fr.Invoke(action, null);
action = () => fr.setMaximumProgressBar(findResults.Items.Count);
fr.Invoke(action, null);
dmd = new List<DailyMailDetails>();
foreach (Item item in findResults.Items)
{
string messageDate = "Error in Date";
string messageSubj = "Error in Subject";
int index = 0;
try
{
PropertySet propertySet = new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.DateTimeSent, ItemSchema.Body, ItemSchema.Subject);
propertySet.RequestedBodyType = BodyType.Text;
EmailMessage message = EmailMessage.Bind(service, item.Id, propertySet);
string temp = startSign.ToUpper();
int start = message.Body.Text.ToUpper().IndexOf(temp) + temp.Length;
int end = message.Body.Text.ToUpper().IndexOf(finishSign.ToUpper());
int len = end - start;
string text = message.Body.Text.Substring(start, len);
index = findDmdIndex(message.DateTimeSent.ToShortDateString().ToString());
if (index == -1)
{
dmd.Add(new DailyMailDetails(message.DateTimeSent.ToShortDateString().ToString(), (List<PeopleSigniture>)Extensions.Clone<PeopleSigniture>(OrginallistPeopleSign)));
index = dmd.Count - 1;
}
bool signExist = false;
for (int i = 0; i < listPeopleSign.Count; i++)
if (text.ToUpper().Contains(dmd[index].peopleSign[i].Signiture.ToUpper()))
{
dmd[index].peopleSign[i].addResponse(message.DateTimeSent.ToString(), message.Subject.ToString());
signExist = true;
break;
}
messageDate = message.DateTimeSent.ToString();
messageSubj = message.Subject.ToString();
if (!signExist)
dmd[index].peopleSign[dmd[index].peopleSign.Count - 2].addResponse(message.DateTimeSent.ToString(), message.Subject.ToString());
}
catch (Exception ex)
{
dmd[index].peopleSign[dmd[index].peopleSign.Count - 1].addResponse(messageDate, messageSubj);
}
action = () => fr.increasePrograss();
fr.Invoke(action, null);
}
}
catch (Exception ex)
{
MessageBox.Show("Class: Mail Function:ReadMail" + ex.Message);
}
Action action2 = () => fr.setText(ToString(true),dmd);
fr.Invoke(action2, null);
}
For issue #1 - you are viewing the XML output likely because you have EWS tracing enabled. You need to set ExchangeService.TraceEnabled to false or comment it out entirely. (You also have many duplicate lines of code you need to cleanup.)
service.TraceEnabled = false;
For issue #2 - you need to determine the actual .NET exception. Without this - we cannot help you further. It could be crashing for countless reasons. Please provide a stack trace.