outlook interop application doesn't get all emails C# - c#

I'm trying to get outlook Email using Microsoft.Office.Interop.Outlook but in cases where the folder has a lot of emails (for example 1904 Emails) I'm getting only 571 emails.
here's my code:
Application oApp = new Application();
_NameSpace oNS = (_NameSpace)oApp.GetNamespace("MAPI");
MAPIFolder inbox = oNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
var emails = inbox.Items;
int emailsCount = emails.Count;
when I open outlook I see the number 1904 next to the Inbox folder, but when I scroll down I see the line "there are more items in this folder on the sever"
dose anyone know how can I download all my Emails using outlook interop?

this is my code from a working app:
A lot of it seems cracking a nut with a sledge hammer however, this hasnt failed me in many years.
MAPIFolder f;
int retries = 0;
while (!connected && retries < 2)
{
doUpdateStatus("Connecting");
try
{
app = new Application();
NameSpace ns = app.GetNamespace("MAPI");
f = ns.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
doUpdateStatus("Connected to outlook");
doUpdateStatus("Walking Outlook Folders .. Please wait");
try
{
doUpdateStatus("");
if (DoSync)
{
try
{
doUpdateStatus("Syncing");
SyncObject _syncObj = null;
_syncObj = ns.SyncObjects.AppFolders;
_syncObj.SyncEnd += _syncObj_SyncEnd;
ns.SendAndReceive(false);
syncing = true;
_syncObj.Start();
while (syncing)
{
Thread.Sleep(10);
}
connected = true;
}
catch
{
doUpdateStatus("Sync failed");
}
finally
{
syncing = false;
}
}
else
{
doUpdateStatus("Outlook sync disabled");
connected = true;
}
}
catch
{
doUpdateStatus("Unable to connect to Outlook and Load folders");
app.Quit();
retries++;
Thread.Sleep(5000);
}
}
catch
{
doUpdateStatus("Unable to connect to Outlook");
if (app!=null) app.Quit();
retries++;
Thread.Sleep(5000);
}
}
private static void _syncObj_SyncEnd()
{
syncing = false;
}

You can either force Outlook to download all items (make sure the slider in the Exchange account properties is set to "All' rather than something like "12 months") or you can reopen the folder in the online mode - in Extended MAPI (C++ or Delphi), you can do that by using the MAPI_NO_CACHE flag when calling IMAPISession::OpenEntry or IMsgStore::OpenEntry. If Extended MAPI is not an option, you can use Redemption (I am its author):
MAPI_NO_CACHE = &H200
MAPI_BEST_ACCESS = &H10
set OutlookFolder = Application.ActiveExplorer.CurrentFolder
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set OnlineFolder = Session.GetFolderFromID(OutlookFolder.EntryID, OutlookFolder.StoreID, MAPI_NO_CACHE + MAPI_BEST_ACCESS)
MsgBox OnlineFolder.Items.Count

Related

c# vsto Outlook.ApplicationEvents_11_NewMailEx

Using Visual Studio 2022
outlook 365 with IMAP account
VSTO addin.
c#
Event : newmaileX to capture every incoming email. If certain subject, then I enter text into the body. If body is html, I find the tag and insert after. I have create a button on ribbon to test, and the email subject is altered and new text is in the body.
fine so far.
When the newmailex is fired, it runs my code, but sometimes it does not save the changes, and sometimes it does.
Why ?
if I add "mailItem.Save()" this works, but I then get duplicates of the same email. Sometimes upto 10 duplicates. Is this an IMAP thing ? Below is my code.
void NewMail_Event(String entryIDCollection)
{
Outlook.NameSpace outlookNS = this.Application.GetNamespace("MAPI");
Outlook.MailItem mailItem = null;
try
{
string sTag;
string sBody;
int nPos;
sTag = "<table border=\"1\" cellspacing=\"0\"><tr bgcolor=\"#f5e942\"><td><font color=\"#FF0000\" size=\"4\">";
sTag += "This email originated from outside and was not listed in our safe senders list.<br>";
sTag += "DO NOT action, click on any links or open attachments unless you recognise the sender and know the content is safe.";
sTag += "</font></td></tr></table><br>";
string sSubject = null;
string filter = "[EXTERNAL]";
string[] sEmails = entryIDCollection.Split(',');
foreach (string sEmail in sEmails)
{
mailItem = (Outlook.MailItem)outlookNS.GetItemFromID(sEmail, Type.Missing);
if (mailItem.Subject != null)
{
File.AppendAllText("c:\\1data\\desktop\\vstolog.txt", mailItem.Subject + "\r\n");
if (mailItem.Subject.Length >= 10)
{
if (mailItem.Subject.ToUpper().StartsWith(filter))
{
sSubject = mailItem.Subject.Substring(filter.Length, mailItem.Subject.Length - filter.Length);
mailItem.Subject = sSubject;
sBody = mailItem.HTMLBody;
if (sBody.Contains("<body>") || sBody.Contains("<BODY>"))
{
if (sBody.Contains("<BODY>"))
{
sBody = sBody.Replace("<BODY>", "<body>" + sTag);
}
else
{
sBody = sBody.Replace("<body>", "<body>" + sTag);
}
}
else
{
if (sBody.Contains("<body") || sBody.Contains("<BODY"))
{
if (sBody.Contains("<body"))
{
nPos = sBody.IndexOf("<body", 0);
}
else
{
nPos = sBody.IndexOf("<BODY", 0);
}
nPos = sBody.IndexOf(">", nPos);
sBody = sBody.Insert(nPos + 1, sTag);
}
else
{
sBody = sTag + sBody;
}
}
if (mailItem.BodyFormat == OlBodyFormat.olFormatHTML)
{
mailItem.HTMLBody = sBody;
}
else
{
mailItem.Body = sBody;
}
//mailItem.Close(OlInspectorClose.olSave);
}
}
}
Marshal.ReleaseComObject(mailItem);
mailItem = null;
}
}
catch (Exception eX)
{
MessageBox.Show(eX.Message);
}
finally
{
if (mailItem != null) Marshal.ReleaseComObject(mailItem);
mailItem = null;
if (outlookNS != null) Marshal.ReleaseComObject(outlookNS);
outlookNS = null;
}
}
You can find similar issues described in case of IMAP profiles configured in Outlook, see IMAP Sent Messages are duplicated and unread in Sent Items folder for more information.
I suppose you are handling the NewMailEx event of the Application class, not the NewMail one. There are several aspects in the code:
string[] sEmails = entryIDCollection.Split(',');
The EntryIDsCollection string contains the Entry ID that corresponds to that item. Note that this behavior has changed from earlier versions of the event when the EntryIDCollection contained a list of comma-delimited Entry IDs of all the items received in the Inbox since the last time the event was fired.
However, depending on the setup on the client computer, after a new message arrives in the Inbox, processes like spam filtering and client rules that move the new message from the Inbox to another folder can occur asynchronously. You should not assume that after these events fire, you'll always get a one-item increase in the number of items in the Inbox.
As a possible workaround you may try to handle the ItemAdd event on the target folder instead.

Outlook VSTO - mailItem body problems

I'm having a problem with email sending in C#.
I'm working on an add-in and everything is going well. I can send my mails, like i want, but not "two times in a row".
For example, my add-in open a Form and after the user action an email is sent.
When the mail is sent, the form is closed and that's okay.
But some time, i need to send two separate emails and the body of second email is always empty. By the way, i fill the "body" of my mails with Word (Microsoft.Office.Interop.Word) to have some formatted text.
If I use the .Body property there is no problem.
Now, I'm wondering if it's not the fault of "Word" because the email part is working but only the body is empty.
I tried to send my mails in the inverse order to see if it's occurs always with the second mail and i was right. It's not about the email or his content but more about being the second sent.
It may be some things which haven't been released yet(not properly released objects) or something like that but i'm doing already it.
That's how i'm doing..
Outlook.MailItem mailItem = (Outlook.MailItem)new Outlook.Application().CreateItem(Outlook.OlItemType.olMailItem);
try
{
mailItem.CC = currentUserExchange.PrimarySmtpAddress;
mailItem.Importance = Outlook.OlImportance.olImportanceHigh;
mailItem.Subject = "XXX";
mailItem.To = finalRecipients;
fillBody(mailItem, mailBody);
mailItem.Send();
}
catch (Exception ex) { }
finally
{
releaseObject(mailItem);
}
if (moderatorPin != String.Empty)
{
Outlook.MailItem mailItemSecurity = (Outlook.MailItem)new Outlook.Application().CreateItem(Outlook.OlItemType.olMailItem);
try
{
mailItemSecurity.Importance = Outlook.OlImportance.olImportanceHigh;
mailItemSecurity.Subject = "XXX";
mailItemSecurity.To = currentUserExchange.PrimarySmtpAddress;
fillBody(mailItemSecurity, mailBodySecure);
mailItemSecurity.Send();
}
catch (Exception ex) { MessageBox.Show("error : " + ex.Message); }
finally
{
releaseObject(mailItemSecurity);
}
}
and :
private void fillBody(Outlook.MailItem mailItem, String bodyMail)
{
Word.Document document = mailItem.GetInspector.WordEditor;
Word.Range rng = document.Paragraphs[1].Range;
try
{
document.Paragraphs[1].LineSpacingRule = Word.WdLineSpacing.wdLineSpaceSingle;
rng.set_Style(Word.WdBuiltinStyle.wdStyleHtmlKbd);
rng.Font.Color = (Word.WdColor)(fontColor.R + 0x100 * fontColor.G + 0x10000 * fontColor.B);
rng.Text = bodyMail;
rng.Select();
}
catch (Exception ex)
{
MessageBox.Show("XXX");
}
finally
{
releaseObject(rng);
releaseObject(document);
}
}

C# Outlook Add-On: Check Calendars Availability

I am working on an add-in for Outlook using C# and I want to be able to check the availability of calendars (mine and others'). I tried using GetSharedDefaultFolder() but it only worked with those who specifically gave me permission, even though all calendars in my company can be viewed by others (we can see the subject and times of appointments). Is there anyway I can get these information? Thanks.
EDIT: I want to emphasize that my problem is with GetSharedDefaultFolder() rather than GetDefaultFolder() (i.e. viewing others' calendars.) Also, I only need to be able to check others' calendars availability, as opposed to having full access to the calendar.
Do not access the folder directly - use Recipient.FreeBusy or AddressEntry.GetFreeBusy
Try This>>
public void GetAllCalendarItems()
{
Microsoft.Office.Interop.Outlook.Application oApp = null;
Microsoft.Office.Interop.Outlook.NameSpace mapiNamespace = null;
Microsoft.Office.Interop.Outlook.MAPIFolder CalendarFolder = null;
Microsoft.Office.Interop.Outlook.Items outlookCalendarItems = null;
oApp = new Microsoft.Office.Interop.Outlook.Application();
mapiNamespace = oApp.GetNamespace("MAPI"); ;
CalendarFolder = mapiNamespace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderCalendar); outlookCalendarItems = CalendarFolder.Items;
outlookCalendarItems.IncludeRecurrences = true;
foreach (Microsoft.Office.Interop.Outlook.AppointmentItem item in outlookCalendarItems)
{
if (item.IsRecurring)
{
Microsoft.Office.Interop.Outlook.RecurrencePattern rp = item.GetRecurrencePattern();
DateTime first = new DateTime(2008, 8, 31, item.Start.Hour, item.Start.Minute, 0);
DateTime last = new DateTime(2008, 10, 1);
Microsoft.Office.Interop.Outlook.AppointmentItem recur = null;
for (DateTime cur = first; cur <= last; cur = cur.AddDays(1))
{
try
{
recur = rp.GetOccurrence(cur);
MessageBox.Show(recur.Subject + " -> " + cur.ToLongDateString());
}
catch
{ }
}
}
else
{
MessageBox.Show(item.Subject + " -> " + item.Start.ToLongDateString());
}
}
}
Seems problem similar to this>
http://www.add-in-express.com/forum/read.php?FID=5&TID=8953
So follow discussion on this link. It might helpful to you.

outlook download email body

I am creating a program that sends a text message and then depending on the reply I want to perform a specific action. Anyways here is my code:
using Microsoft.Office.Interop.Outlook;
using Outlook = Microsoft.Office.Interop.Outlook;
static void Main()
{
var outlook = new Microsoft.Office.Interop.Outlook.Application();
// fire event when a new email arives
outlook.NewMailEx += new ApplicationEvents_11_NewMailExEventHandler(oApp_NewMailEx);
// etc
}
static void oApp_NewMailEx(string EntryIDCollection)
{
var outlook = new Microsoft.Office.Interop.Outlook.Application();
MailItem temp = (MailItem)outlook.Session.GetItemFromID(EntryIDCollection, Missing.Value);
var body = temp.Body; // the body of the email is null! I tried waiting and it is null until I open it...
Console.WriteLine(body);
}
This part is not important but I send the "text message" with this function:
// send text message "att.txt.net only works with at&t phones"
public static int SendEmail(string recipeint = "9546543930#att.txt.net")
{
try
{
// Create the Outlook application by using inline initialization.
Outlook.Application oApp = new Outlook.Application();
//Create the new message by using the simplest approach.
Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
Outlook.Accounts accounts = oMsg.Session.Accounts;
foreach (Outlook.Account account in accounts)
{
// When the e-mail address matches, send the mail.
if ( account.SmtpAddress.Contains("gmail") )
{
oMsg.SendUsingAccount = account;
break;
}
}
// If you want to, display the message.
oMsg.Display(true); //modal
//Add a recipient.
Outlook.Recipient oRecip = (Outlook.Recipient)oMsg.Recipients.Add(recipeint);
oRecip.Resolve();
//Set the basic properties.
oMsg.Subject = "This is the subject of the test message";
oMsg.Body = "This is the text in the message.";
//Add an attachment.
// TODO: change file path where appropriate
//String sSource = "C:\\setupxlg.txt";
//String sDisplayName = "MyFirstAttachment";
//int iPosition = (int)oMsg.Body.Length + 1;
//int iAttachType = (int)Outlook.OlAttachmentType.olByValue;
//Outlook.Attachment oAttach = oMsg.Attachments.Add(sSource, iAttachType, iPosition, sDisplayName);
//Send the message.
oMsg.Save();
oMsg.Send();
//Explicitly release objects.
oRecip = null;
//oAttach = null;
oMsg = null;
oApp = null;
}
// Simple error handler.
catch (System.Exception e)
{
Console.WriteLine("{0} Exception caught: ", e);
}
//Default return value.
return 0;
}
So I am able to send an email with my gmail account and when I reply to the text message the function oApp_NewMailEx gets executed with the id of the new email. I am able to get the subject but the body does not get downloaded until I hover my mouse over the email or open the email. I already waitied 2 minutes on another thread and then tried to see the body and it was still null.
Edit note to make this work I have:
It looks gray out because I did not run outlook as an administrator. If You run outlook as an admin you will be able to update the security settings.
I also imported the Microsoft Outlook 14.0 Object library as a reference.
Once I received the email I called the send and receive method. wait a little and then I was able to read the body.
outlook.Session.SendAndReceive(false);

Outlook returns error: The messaging interface has returned an unknown error

I am having some problems with a piece of code, I am trying to import data from a source (at this time an access database) into a custom form but i keep getting the above error.
When i use a VBscript inside the source database all contacts import correctly.
When i repair the PST it still gives this error.
When i add a delay of 450 ms. the error also occurs but later on in the process.
Having Outlook opened or closed does not matter.
I am using the following method
string[] arrFolders = strFolders.Split('\\');
Outlook.Application app = null;
Outlook.MAPIFolder folder = null;
try {
app = new Outlook.Application();
folder = app.GetNamespace("MAPI").Folders[arrFolders[0]];
} catch (Exception ex) {
writeLogLine("Error creating Outlook instance: " + ex.Message);
MessageBox.Show("Error creating Outlook instance\r\n" + ex.Message);
intErrorCount++;
blnHasErrors = true;
blnAbort = true;
}
try {
for (int i = 1; i < arrFolders.Length; i++) {
folder = folder.Folders[arrFolders[i]];
}
} catch (Exception ex) {
writeLogLine("Error navigating to DRM folder: " + ex.Message);
MessageBox.Show("Error navigating to DRM folder\r\n" + ex.Message);
intErrorCount++;
blnHasErrors = true;
blnAbort = true;
}
setProgressbarMaximum(dtResults.Rows.Count);
setProgressbarMode(ProgressBarStyle.Continuous);
//int intRowCount = 0;
foreach (DataRow drItem in dtResults.Rows) {
if (strDRMType == "Contact") {
try {
Outlook.ContactItem x = (Outlook.ContactItem)folder.Items.Add("IPM.Contact." + strFormName);
for (int i = 0; i < arrMappings.GetLength(0); i++) {
if (arrMappings[i, 1] != null && drItem[arrMappings[i, 0]].ToString() != "") {
x.UserProperties[arrMappings[i, 1]].Value = drItem[arrMappings[i, 0]].ToString();
}
}
x.Save();
} catch (Exception ex) {
writeLogLine("Error importing contact: " + ex.Message);
intErrorCount++;
blnHasErrors = true;
}
}
as i said, when i loop the code it will throw exceptions after 100 to 200 contacts, when i add a delay it will get to contact 400/500 before failing.
This code is supposed to be for a generic import tool for this specific form so there is no need for hardcoding the source column names to the form fields in the import code.
Any help is appreciated.
I'm assuming this is not an Outlook add-in, since you say it doesn't matter if OL is open or closed, right?
One thing you may want to do is ensure you are releasing the COM objects once you are done with them, using System.Runtime.InteropServices.Marshal.ReleaseComObject(...). Also, when you use dot notation like "namespace.Folders[..].Name" you are actually leaking a reference to both the Folders collection object and a Folder object.
When you do folders.Items.Add(...) inside a loop, that leaks a lot of objects.
So, clean up your COM references first, and see how that affects your situation.
Here's how I typically use COM objects:
MyComLib.Foo foo = null;
try
{
foo = new MyComLib.Foo();
foo.DoSomething();
} catch(COMException exc)
{
// handle error, or rethrow
}
finally
{
if(foo != null)
Marshal.ReleaseComObject(foo);
}

Categories

Resources