Windows application invokes business logic
Business logic creates new e-mail using Exchange Web Services and returns Entry ID of e-mail to Windows application
Windows application attempts to find and display new e-mail via Outlook Interop based on the Entry ID of the e-mail.
The above doesn't work when using Cached Exchange Mode. Outlook only checks the local cache for the message, and since it was just created on the server, it won't be immediately available locally.
However, it works just fine when the account isn't using Cached Exchange Mode, because Outlook checks the Exchange Server for the e-mail.
So, the question:
How do I ensure that Outlook checks the Exchange Server instead of the local cache, or at least syncs with the server before looking for the message?
Here's the (simplified) code we use to display e-mails based on their Entry IDs:
void ShowEmail(string entryId)
{
// (COM release and error handling removed for readability)
var app = new Microsoft.Office.Interop.Outlook.Application();
var ses = app.Session;
var mailItem =
(Microsoft.Office.Interop.Outlook.MailItem)ses.GetItemFromID(entryId);
mailItem.Object.Display(true);
}
You have no control over the upload or sync of the mailbox. See this post. If the user is using Cached Exchange Mode - they can't use this feature.
If you have access to the registry - you could try disabling Cached Exchange Mode, and then re-enabling it. See this post which modifies the registry to enable/disable CEM.
Related
I'm working on a plugin for Outlook. I need to always have an up-to-date list of Outlook accounts (File->Add Account), but when I take this data from NameSpace.Accounts, they are relevant only at the time Outlook starts. If I add another account or delete the old one, these changes will not be reflected in NameSpace.Accounts. Is there any way to refresh this data?
I am using the following code to get accounts
var outlookObj = new Outlook.Application();
var accounts = outlookObj.Application.Session.Accounts;
foreach (Outlook.Account account in accounts)
{
//do something
}
Firstly, do not use new Outlook.Application() in an addin - an instance of the Application object is provided to your addin on startup, and it is not handicapped by the security prompts..
Also try to avoid caching/keeping a reference to the Accounts or Account object.
If using Redemption is an option (I am its author), it exposes RDOAccounts collection (which is never cached) and, unlike the Accounts collection in OOM, also exposes events when accounts are added/deleted/modified/rearranged.
The Outlook object model doesn't provide such events for accounts. But you may try to handle the Stores.StoreAdd event which is fired when a Store has been added to the current session either programmatically or through user action.
Note, as a possible workaround you may consider using a third-party library such as Redemption which can monitor changes to Accounts in Outlook.
There is no need to create a new Application instance in the code:
var outlookObj = new Outlook.Application();
Instead, in VSTO based add-ins you need to use the ThisAddin class where the Application property is provided out of the box.
We want to access mailboxes via EWS (Exchange Web Services) with an dedicated user who has no own mailbox.
The target is to cover all Exchange Server version 2007-2019.
Reason why we want to have an dedicated user with no mailbox: We want analyze all mailboxes in an Exchange Server by an software. But therefore we not really need an user and even an mailbox. Only the data inside the mailboxes are interesting for the software.
We use Independentsoft´s API to access the EWS:
var lCredential = new NetworkCredential("ADUserWithNoMailbox", "Password");
m_Service = new Service("https://hostname/EWS/Exchange.asmx", lCredential);
try
{
FindFolderResponse lResponse = m_Service.FindFolder(StandardFolder.MailboxRoot);
// [...]
}
catch (Exception e)
{
// cast in into multiple expected types
var lServiceRequestException = e as Independentsoft.Exchange.ServiceRequestException;
if (lServiceRequestException.ResponseCode == "ErrorNonExistentMailbox")
{
// lServiceRequestException.Message shows: "No mailbox with such guid."
// [...]
}
// [...]
throw;
}
Our user ADUserWithNoMailbox which is in the Active Directory has no mailbox. Therefore an exception occurs with the message:
"No mailbox with such guid."
Question: How can we access the exchange mailboxes via EWS when the user has no own mailbox?
It should work okay if the servers are patched to the correct levels eg there can be problem like https://support.microsoft.com/en-us/topic/-the-smtp-address-has-no-mailbox-associated-with-it-error-when-you-access-a-user-s-mailbox-by-using-ews-application-c8e31e36-b6e2-229e-cc78-305ab9fea94a. I've always found this to be problematic if your deploying apps in different customer environments and found for most OnPrem deployments giving the Service account your using a Mailbox is not a problem, to stop it appearing in address lists most customers can just hide it. (Office365 is a different matter because of the cost of consuming a licence but you can use App tokens which don't require a user or mailbox)
Probably for your requirement using EWS Impersonation https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/impersonation-and-ews-in-exchange is a better option as that will give you access to all Mailboxes.
I've been successfully sending out appointment invites with outlook through c# in an asp.net application. I'm using the following code:
//send out the outlook notification
Outlook.Application outlookApp = new Outlook.Application();
Outlook.AppointmentItem newMeeting = outlookApp.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olAppointmentItem) as Outlook.AppointmentItem;
if (newMeeting != null)
{
newMeeting.MeetingStatus = Microsoft.Office.Interop.Outlook.OlMeetingStatus.olMeeting;
newMeeting.Location = "TBD";
newMeeting.Subject = "New SEB Consult";
newMeeting.Body = "A new meeting has been scheduled. If you're a member of the team, please accept";
newMeeting.Start = meetingDate;
newMeeting.Duration = 60;
Outlook.Recipient recipient = newMeeting.Recipients.Add("Smith John");
recipient.Type = (int)Outlook.OlMeetingRecipientType.olRequired;
((Outlook._AppointmentItem)newMeeting).Send();
}
This works, but my problem is that it's sending them from my email which I'm logged into with outlook on the same computer. I'd like to send them from a different email, so that they appear more like system notifications coming from my application rather than a personal email. I do have the username and password for the account, but the application is eventually going to be run on a remote server, so I can't just log into outlook with another email. Nothing I've been able to find changes the sender. Does anyone have any more information on how to change these credentials, or where it looks for the credentials?
You can't use OLE if you would like to control the emails. OLE is just to control the local outlook instance which is tied to the running account.
You must use the exchange API instead. With it you can create an appointment like described in this MSDN article: How to: Create appointments and meetings by using EWS in Exchange 2013
Appointment appointment = new Appointment(service);
// Set the properties on the appointment object to create the appointment.
appointment.Subject = "Tennis lesson";
appointment.Body = "Focus on backhand this week.";
appointment.Start = DateTime.Now.AddDays(2);
appointment.End = appointment.Start.AddHours(1);
appointment.Location = "Tennis club";
appointment.ReminderDueBy = DateTime.Now;
// Save the appointment to your calendar.
appointment.Save(SendInvitationsMode.SendToNone);
// Verify that the appointment was created by using the appointment's item ID.
Item item = Item.Bind(service, appointment.Id, new PropertySet(ItemSchema.Subject));
Console.WriteLine("\nAppointment created: " + item.Subject + "\n");
The library is open source and available at github.
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution. Read more about that in the Considerations for server-side Automation of Office article.
You may consider using the EWS Managed API, EWS, and web services in Exchange instead.
I am getting message id (using propertyaccessor) in outlook for microsoft exchange emails for sent items if not using cached mode.
But, in cached mode, it is empty.
How to get it in cached mode ?
The cached store does not sync that property from the Exchange store for the Sent Items folder - it is a performance optimization: when a message is sent in the cached mode, Outlook hands it over to the server, and creates a sent message in the local copy of the Sent Items folder. Server sends the message and creates a message in the server version of the folder. In theory, the two messages look the same to the user and do not need to be synchronized. But the message id is of course missing from the local copy.
On the low (Extended MAPI) level, you would need to reopen the message in the online mode using the MAPI_NO_CACHE flag. You cannot do this using the Outlook Object Model alone or Extended MAPI (since it requires C++ or Delphi). If using Redemption (I am its author) is an option, it will let you reopen a message in the online mode. In VB script, you could do the following (C# would be very similar):
MAPI_NO_CACHE = &H200
MAPI_BEST_ACCESS = &H10
PR_INTERNET_MESSAGE_ID_W = "http://schemas.microsoft.com/mapi/proptag/0x1035001F"
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set Msg = Session.GetMessageFromID(Application.ActiveExplorer.Selection(1).EntryID, , MAPI_NO_CACHE + MAPI_BEST_ACCESS)
MsgBox Msg.Fields(PR_INTERNET_MESSAGE_ID_W)
We're using Exchange 2007 WS to process mail folders and are hitting various problems if we try and forward a message we've already received. Our process is:
Windows Service monitors mailbox folder, on finding a new mail we process the information and move the item to a 'Processed folder' and store the Exchange Message Id.
Users may opt to forward the mail externally. We use the Exchange API to find the item using the Message Id we stored earlier, and then again use the API to forward.
Except finding the mail again is proving rather flaky. We regularly get the following error:
The specified object was not found in the store.
Is there a better/more reliable way we can achieve the same? The documentation for Exchange WS is rather sparse.
This is a bug in microsoft exchange manage API. here is a link for more information
http://maheshde.blogspot.com/2010/09/exchange-web-service-specified-object.html
Are you saving the Message ID of the newly found message or the message once it has been moved to the 'Processed' folder? The id will change when it moves to a new folder.
The method recommended in the book Inside Microsoft Exchange Server 2007 Web Services is to grab the PR_SEARCH_KEY (0x300B, Binary) of the newly discovered item, then move it to the 'Processed' folder. You can then search for it in the new folder based on the PR_SEARCH_KEY and get it's new Message id to forward it.
I have come to the conclusion that this happens to me is because while my app is processing the emails, someone else is fiddling with an email at the same time.
So to cure the problem, I put it the code in a try catch and see if the exception is == the that object not found in store, if so I just skip it and move on to the next item. So for has no issues.
I wrote a program that reads the emails in inbox downloads attachments to the specified folder, wrote the email info and the saved path to the database, and finally deletes the email. I run this program as a windows service. After all tests are finished I run this program to the main server and run it. Program runs successfully but sometimes I got this error. I checked everything and finally I found that I forgot to stop service on my computer. 2 programs that runs on my computer and on real server checking the same mailbox at the same time. If you get this error make sure that only one program can process at the same mailbox.