Outlook error in inbox folder / MAPIFolder C# (Microsoft.Office.Interop) - outlook

i always have the following errors in my inbox:
Native View To inspect the native object, enable native code debugging.
I have the following code:
public void CheckForEmails()
{
Outlook._Application _app = new Outlook.Application();
Outlook._NameSpace _ns = _app.GetNamespace("MAPI");
Outlook.MAPIFolder inbox = _ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
_ns.SendAndReceive(true);
List<Outlook.MailItem> ReceivedEmail = new List<Outlook.MailItem>();
Outlook.Items items = inbox.Items;
foreach (Outlook.MailItem mail in inbox.Items)
ReceivedEmail.Add(mail);
}
I have two mail addresses set up in Outlook.
IMAP and Exchange.
Perhaps relevant to mention.

First of all, don't use the foreach loop with COM objects. You will not be able to release COM objects in a timely manner and can reach the limit of COM references hold with the Exchange server.
The Items class from the Outlook object model is a collection of items that can represent your managed list of emails.

Related

MailItem.GetConversation() on shared mailbox

I am using following code to display properties from original email in conversation.
void DemoConversation()
{
object selectedItem =
Application.ActiveExplorer().Selection[1];
// For this example, you will work only with
//MailItem. Other item types such as
//MeetingItem and PostItem can participate
//in Conversation.
if (selectedItem is Outlook.MailItem)
{
// Cast selectedItem to MailItem.
Outlook.MailItem mailItem =
selectedItem as Outlook.MailItem; ;
// Determine store of mailItem.
Outlook.Folder folder = mailItem.Parent
as Outlook.Folder;
Outlook.Store store = folder.Store;
if (store.IsConversationEnabled == true)
{
// Obtain a Conversation object.
Outlook.Conversation conv =
mailItem.GetConversation();
// Check for null Conversation.
if (conv != null)
{
// Obtain Table that contains rows
// for each item in Conversation.
Outlook.Table table = conv.GetTable();
Debug.WriteLine("Conversation Items Count: " +
table.GetRowCount().ToString());
Debug.WriteLine("Conversation Items from Table:");
while (!table.EndOfTable)
{
Outlook.Row nextRow = table.GetNextRow();
Debug.WriteLine(nextRow["Subject"]
+ " Modified: "
+ nextRow["LastModificationTime"]);
}
Debug.WriteLine("Conversation Items from Root:");
// Obtain root items and enumerate Conversation.
Outlook.SimpleItems simpleItems
= conv.GetRootItems();
foreach (object item in simpleItems)
{
// In this example, enumerate only MailItem type.
// Other types such as PostItem or MeetingItem
// can appear in Conversation.
if (item is Outlook.MailItem)
{
Outlook.MailItem mail = item
as Outlook.MailItem;
Outlook.Folder inFolder =
mail.Parent as Outlook.Folder;
string msg = mail.Subject
+ " in folder " + inFolder.Name;
Debug.WriteLine(msg);
}
// Call EnumerateConversation
// to access child nodes of root items.
EnumerateConversation(item, conv);
}
}
}
}
}
void EnumerateConversation(object item,
Outlook.Conversation conversation)
{
Outlook.SimpleItems items =
conversation.GetChildren(item);
if (items.Count > 0)
{
foreach (object myItem in items)
{
// In this example, enumerate only MailItem type.
// Other types such as PostItem or MeetingItem
// can appear in Conversation.
if (myItem is Outlook.MailItem)
{
Outlook.MailItem mailItem =
myItem as Outlook.MailItem;
Outlook.Folder inFolder =
mailItem.Parent as Outlook.Folder;
string msg = mailItem.Subject
+ " in folder " + inFolder.Name;
Debug.WriteLine(msg);
}
// Continue recursion.
EnumerateConversation(myItem, conversation);
}
}
}
It works fine on my personal inbox and shared mailbox added as additional inbox.
But all other shared mailboxes which I have full access but have auto-mapped in my Outlook client doesn't work.
Does anyone know if mailItem.GetConversation() supposed to work with shared mailboxes which are not added as additional account but are auto-mapped?
Because on these shared mailboxes, I get Conversation Items Count: 0even if there are other emails in the same conversation.
Thank you.
It works fine on my personal inbox and shared mailbox added as additional inbox.
It seems you just added a second account to the profile, not a shared mailbox.
GetConversation returns Null (Nothing in Visual Basic) if no conversation exists for the item. No conversation exists for an item if the store does not support Conversation view (for example, Outlook is running in classic online mode against a version of Microsoft Exchange earlier than Microsoft Exchange Server 2010).
Use the IsConversationEnabled property of the Store object to determine whether the store supports Conversation view and GetConversation is supposed to work.
Indeed, GetRootItems() return 0 for shared mailbox which is frustrating because Outlooks shows the mails as Conversations. What I have noticed is, that each email in Inbox of that shared mailbox has ConversationID assigned correctly, so solution is to iterated the folder and build own conversation collection based on ConversationID value. It contains not only incoming messages but also sent items, so really all elements of conversations. It works as charm at least for my purpose which was to calculate response time for that shared mailbox and average length of conversations.

Uniquely identify Mailitem

I need to store a model for every used MailItem. For this I've written following Method
private readonly static Dictionary<string, PermitCustomPaneViewmodel> ViewmodelLookup = new Dictionary<string, PermitCustomPaneViewmodel>();
public static PermitCustomPaneViewmodel CreateOrGet(MailItem c)
{
if (c.EntryID == null)
c.Save();
if (!ViewmodelLookup.ContainsKey(c.EntryID))
{
var vm = new PermitCustomPaneViewmodel(c);
c.Unload += () => ViewmodelLookup.Remove(c.EntryID);
ViewmodelLookup.Add(c.EntryID, vm);
}
return ViewmodelLookup[c.EntryID];
}
When the Model already exists, I look it up and return it. If it was not created, I create it and remove the entry after the MailItem will be unloaded.
However I have observed that the MailItem object will not be vailid all the time untill unload is called. In order to reliable identify the MailItem I used the EntryID. The problem now is this only works if the Item is saved.
So currently I save the Item if no EntryID was found. But this automaticly saves the item under draft.
Is there a way to distingush MailItem's that is not saved in a way so it can be used in a Dictionary<,>.
New created items don't have the EntryID property set. Get the ID assigned by the store provider you must save it. If you need to identify a new MailItem object you may consider adding a user property to the item by using the UserProperties.Add method which reates a new user property in the UserProperties collection. For example:
Sub AddUserProperty()
Dim myItem As Outlook.ContactItem
Dim myUserProperty As Outlook.UserProperty
Set myItem = Application.CreateItem(olContactItem)
Set myUserProperty = myItem.UserProperties _
.Add("LastDateSpokenWith", olDateTime)
myItem.Display
End Sub
Be aware, the Entry ID changes when an item is moved into another store, for example, from your Inbox to a Microsoft Exchange Server public folder, or from one Personal Folders (.pst) file to another .pst file. Solutions should not depend on the EntryID property to be unique unless items will not be moved. Basically it works fine as long as the message is staying in its parent folder or it may be changed if the Outlook item is moved to a different folder (depends on the store provider).
You may also consider using the message id from the message MIME header (PR_INTERNET_MESSAGE_ID and PR_TRANSPORT_MESSAGE_HEADERS). But they are not set on newly created items. These properties are available on the message received from an SMTP server or through the SMTP connector.

outlook vsto sending mail

I've been struggling with this for a while now and I can't get an answer anywhere.
I made an outlook add in which has a ribbon and two buttons, The one button opens up a mailitem where you can compose your mail and then the 2nd button sends the mail.
In the background it takes all of the recipients and adds it to the bcc field and sends the mail in batches for instance if there are 100 recipients it will send to 25 people at time.
So my problem is that it works perfectly on the developer PC but the send button doesn't work on the end user PC. The add in loads registries are fine and it targets the right .Net framework everything!
private void CreateEmailItem(Outlook.Recipient strRecipientAddressTo)
{
string strFilePath = #"c:\temp\OutlookAttachments";
string[] strFiles = Directory.GetFiles(strFilePath);
bool bFileExists = Directory.Exists(strFilePath);
Outlook.MailItem eMail = (Outlook.MailItem)
Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem);
Outlook.MailItem mailItem = Globals.ThisAddIn.Application.ActiveInspector().CurrentItem as Outlook.MailItem;
eMail.Subject = mailItem.Subject;
eMail.BCC = mailItem.To;
eMail.Body = mailItem.Body;
if (bFileExists)
{
foreach (string file in strFiles)
{
File.SetAttributes(file, FileAttributes.Normal);
eMail.Attachments.Add(file);
}
}
((Outlook._MailItem)eMail).Send();
}
When the send button on the ribbon is clicked this method is called, but on end user the button just doensn't fire .. can this be permissions ? or any advice would be very much appreciated !!!!
It is hard to suggest there but did you add any logging there. There can be chances that you are getting some crash in following line..
email.Attachments.Add(file)
And thats why it is not reaching until send statement. You can check the event logs on user's system as well. They might help you.

EWS Managed API 2.2 Read\Write extended properties of attachments

Currently I'm working on migration of one big project from MAPI CDO to EWS (Managed API 2.2) to support Ex2016. All things were migrated well except one: I can't find the way how to read\write Attachments Extended Properties. Does anybody know how to do that or may be some workaround? This is very critical for me and I would be very appreciate for any help.
---Update:
Also tried to use native EWS to get property of attachment but without success too:
var ret = esb.GetAttachment(new GetAttachmentType()
{
AttachmentIds = new []{new AttachmentIdType()
{
Id = "AAMkADVhNjUzMzMyLTRiMDYtNDc4OS1hYjJjLWI1ZDA4ZWFhYTJkZQBGAAAAAADqFaOFYZSeQI5UObwGbjIJBwAOgaos6ORVS5+o5bQovn/kAAAAeN2cAAAOgaos6ORVS5+o5bQovn/kAAAeCoIuAAABEgAQAJPAuRg2gipPmEKfgW26mFU=",
}},
AttachmentShape = new AttachmentResponseShapeType()
{
BodyType = BodyTypeResponseType.Best,
BodyTypeSpecified = true,
IncludeMimeContent = false,
IncludeMimeContentSpecified = true,
AdditionalProperties = new []
{
new PathToExtendedFieldType() { PropertyType = MapiPropertyTypeType.Integer, PropertyTag = "0x3705"},
new PathToExtendedFieldType() { PropertyType = MapiPropertyTypeType.Integer, PropertyTag = "0x0E21"},
}
}
});
The response doesn't contain any of requested properties.
--- Update 2:
In project we use next properties of attachments:
PR_RECORD_KEY, PR_DISPLAY_NAME, PR_RENDERING_POSITION
PR_ATTACH_ENCODING, PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_ATTACH_CONTENT_ID, PR_ATTACH_FLAGS, PR_ATTACH_MIME_TAG, PR_ATTACH_CONTENT_LOCATION, PR_ATTACH_SIZE
Also we create a couple of Custom Extended Properties with custom Property Set and tag some attachments with that props.
Some of Properties can be found in object model of EWS/ManagedApi like PR_ATTACH_SIZE but the problem with others and with custom props.
So we need to read/write standard attachment properties as well as custom.
In project we mark attachment itself, not embedded Item.
You can't access extended properties on Attachments or the Recipients collection in EWS outside of those properties that are made accessible as strongly typed properties by the API. The only place you can use Extended properties are at the message level.
That said can you explain more as to how your using Extended properties eg are these extended properties on embeded items. If that is the case then you could access those extended properties via the Item Attachment.
Looking at your code 0x3705 is the PR_ATTACH_METHOD property on an attachment there is no equivalent to this in EWS, rather EWS will return a different Attachment Class based on the Attachment type. Eg ItemAttachment, FileAttachment or ReferanceAttachment (eg for OneDrive Attachments). 0x0E21 is that Attachment number EWS is going to return the Attachments in the order of that number in GetItem request so you can compute that yourself. But the property is useless in EWS because to get an Attachment you need the EWSId unlike MAPI.
Cheers
Glen

Send a mail from outlook by getting To list from SQl server

I am stuck with a issue from 5 days.
I need a way to attain following requirement.
mailing list is present in Database(SQL server)
I have a mail in Outlook
now i have to send mail to all the 200,000 mail ids in Database
**Note one mail can have only 200 mail IDs so
200,000/200=1000 mails **Note: this 200,000 count is not fixed it will decrease and increase>
like jhon#xyz.com will be present today , next day we may need not send to him
his name might be completely removed (so DL is not an option)
I need a way to automate this
All i have a sleep less nights and coffee cups on my desk
I work in ASP.net any PL which meets this need is fine.
I assume that you know how to create sql statement for what you need and how to retrieve data from database in .NET. This means that only issue is actually sending this from outlook.
Here is an article that describes this in detail and piece of code copied from there.
using System;
using System.Text;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace OutlookAddIn1
{
class Sample
{
public static void SendEmailFromAccount(Outlook.Application application, string subject, string body, string to, string smtpAddress)
{
// Create a new MailItem and set the To, Subject, and Body properties.
Outlook.MailItem newMail = (Outlook.MailItem)application.CreateItem(Outlook.OlItemType.olMailItem);
newMail.To = to;
newMail.Subject = subject;
newMail.Body = body;
// Retrieve the account that has the specific SMTP address.
Outlook.Account account = GetAccountForEmailAddress(application, smtpAddress);
// Use this account to send the e-mail.
newMail.SendUsingAccount = account;
newMail.Send();
}
public static Outlook.Account GetAccountForEmailAddress(Outlook.Application application, string smtpAddress)
{
// Loop over the Accounts collection of the current Outlook session.
Outlook.Accounts accounts = application.Session.Accounts;
foreach (Outlook.Account account in accounts)
{
// When the e-mail address matches, return the account.
if (account.SmtpAddress == smtpAddress)
{
return account;
}
}
throw new System.Exception(string.Format("No Account with SmtpAddress: {0} exists!", smtpAddress));
}
}
}
What I would suggest is to skip using outlook unless that’s really necessary and send email by directly communicating with SMTP server.
Just search for “how to send email from C#” or something similar and you’ll find a ton of examples.

Resources