Outlook custom plugin code not working as expected (Downlaod Email attachment) - outlook

I am tring to save attachemnt from a incoming mail in outllok. This is my code. My issue is it downloads correctly when email arrives(when my laptop is open), but this mail is scheduled everyday at 6:00 AM, I open my laptop at 9 and mail is already present and it is not downloading as expected?Do i need to do anything with code?
const string destinationDirectory = #"\\prod_data\Service Now\";
Outlook.MAPIFolder inBox = this.Application.ActiveExplorer()
.Session.GetDefaultFolder(Outlook
.OlDefaultFolders.olFolderInbox);
Outlook.Items inBoxItems = inBox.Items;
Outlook.MailItem newEmail = null;
inBoxItems = inBoxItems.Restrict("[Unread] = true");
try
{
foreach (object collectionItem in inBoxItems)
{
newEmail = collectionItem as Outlook.MailItem;
if (newEmail != null)
{
if (newEmail.Attachments.Count > 0)
{
for (int i = 1; i <= newEmail
.Attachments.Count; i++)
{
if (newEmail.Attachments[i].FileName.Contains( "LogicView Issue Report"))
{
newEmail.Attachments[i].SaveAsFile(destinationDirectory +
newEmail.Attachments[i].FileName);
}
}
}
}
}
}

I'd suggest checking out the MarkForDownload property value. It returns an OlRemoteStatus constant that determines the status of an item once it is received by a remote user. For example:
Sub DownloadItems()
Dim mpfInbox As Outlook.Folder
Dim obj As Object
Dim i As Integer
Set mpfInbox = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
'Loop all items in the Inbox folder
For i = 1 To mpfInbox.Items.Count
Set obj = mpfInbox.Items.Item(i)
'Verify if the state of the item is olHeaderOnly
If obj.DownloadState = olHeaderOnly Then
MsgBox ("This item has not been fully downloaded.")
'Mark the item to be downloaded.
obj.MarkForDownload = olMarkedForDownload
End If
Next
End Sub
You can use the Start method of the SyncObject class to begin synchronizing a user's folders using the specified Send\Receive group.

Do not use Application.NewMail event - it fires only when Outlook is running at the time the email is received by the Exchange server.
Use Items.ItemAdd event on the Inbox folder (Namespace.GetDefaultFolder(olFolderInbox)) - it will fire when the email downloaded to the cached store when Outlook synchronizes the Inbox folder (assuming you are using cached mode). If Outlook is online, no events will fire. In that case, you can use Items.Find/FindNext to process all unread messages ([Unread] = 'true').
//declare on the global/class level to make sure
//it does not get garbage collected
private Outlook.Items inBoxItems;
...
//in your addin startup code
inBoxItems = inBox.Items
inBoxItems.ItemAdd += inboxItemsItemAdd;
...
private void inboxItemsItemAdd(object item)
{
...
}

Related

Outlook VSTO - Create Mail and save it in Inbox - Set Sender using Outlook Redemption

I basically want to create emails which shall be displayed in the Outlook Inbox using C# Outlook VSTO AddIn.
I have installed the test dlls for Outlook Redemption in my C# Outlook VSTO Addin.
For testing purposes I created a Ribbon Bar with a button. When the button is clicked the following event is triggered:
private void CreateMailItemWithRedemption()
{
//FYI: outlookApp is set in Ribbon load event
//Outlook.Application outlookApp = Globals.ThisAddIn.Application as Microsoft.Office.Interop.Outlook.Application;
var outlookNameSpace = outlookApp.GetNamespace("MAPI");
RDOSession session = new RDOSession();
session.MAPIOBJECT = outlookNameSpace.MAPIOBJECT;
RDOFolder folder = session.GetDefaultFolder(rdoDefaultFolders.olFolderInbox);
RDOMail msg = folder.Items.Add("IPM.Note");
msg.Sent = true;
DateTime dt = new DateTime(2021, 8, 29, 5, 10, 20, DateTimeKind.Utc);
msg.ReceivedTime = dt;
msg.Subject = "Mail created with Redemption";
msg.To = “******#outlook.com”;
msg.Sender = GetAddressEntry("[TestFirstName] [TestLastName]");
msg.Save();
}
It basically works – but for the time being I am stuck with setting the Sender for the new RDOMail which I understand needs to be an RDOAddressEntry.
The GetAddressEntry method looks as follows (with firstname string + lastname string of an existing contact as parameter, like “John Do”):
private RDOAddressEntry GetAddressEntry(string _name)
{
RDOSession session = new RDOSession();
session.MAPIOBJECT = outlookApp.Session.MAPIOBJECT;
RDOAddressList contacts = session.AddressBook.GAL;
RDOAddressEntry contact = contacts.ResolveName(_name);
MessageBox.Show(contact.ToString());
return contact;
}
At contacts.ResolveName an exception is thrown. Do you have an idea what I am doing wrong?
Any hints are welcomed.
Many thanks in advance
Alexander

Not able to save a mailItem with protected attachment in outlook using c#

I'm trying to create a copy of a mailItem in my sent folder. Once I create it, I save the msg in the folder. It works for all mailItems , except when I try to save a mailItem with an attachment where I disallow the save attachment permission in outlook. Why does the mailItem.Save() not saving the mailItem only for this scenario?
In the code below, I'm using redemptions to create a copy in sent folder. msg.save() saves all mails but the one I mentioned above. Also I tried saving the mailItem before the creation, but it does not generate entryId.
static void CreateSentFolderMail(Redemption.SafeMailItem newSentMail, string nvdID, Outlook.MailItem mailItem, Redemption.SafeMailItem safeMailItem)
{
RDOFolder folder = Globals.ThisAddIn.session.GetDefaultFolder(rdoDefaultFolders.olFolderSentMail);
RDOMail msg = (RDOMail)folder.Items.Add(newSentMail);
RDOMail originalmsg = Globals.ThisAddIn.session.GetMessageFromID(mailItem.EntryID);
msg.Sent = true;
msg.SentOn = DateTime.Now;
msg.ReceivedTime =msg.CreationTime;
msg.Subject = safeMailItem.Item.Subject;
msg.To = safeMailItem.Item.To;
msg.BCC = safeMailItem.Item.BCC;
msg.Body = safeMailItem.Item.Body;
msg.Recipients = originalmsg.Recipients;
msg.Sender = Globals.ThisAddIn.session.CurrentUser;
msg.SentOnBehalfOf = Globals.ThisAddIn.session.CurrentUser;
msg.SetProps(NVDMailHeaderUtils.PS_INTERNET_HEADERS + NVDMailHeaderUtils.NVD_HEADER_ID, nvdID);
msg.Save();
}
I had used session.GetRDOObjectFromOutlookObject before calling this method to get a RDOAttachment object. But after using this: session.GetRDOObjectFromOutlookObject I was not able to the save the mailitem. Save was not getting executed and hence the EntryId was not getting generated. Due to this issue I was getting an error here : RDOMail originalmsg = Globals.ThisAddIn.session.GetMessageFromID(mailItem.EntryID); saying "invalid entry Id". I installed the new version of redemptions that solved this problem.

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.

Storing emails in sent items of Outlook using add in

I am trying to develop an add in for Outlook in Visual Studio under .net framework 4.0. I used smtp protocol for sending an email from my Outlook addin. I am not able to find the sent mail in sent folder of Outlook.
How do I store sent mail in the sent folder of Outlook?
Till now I have written this code for sending mail.
public bool SendEMail(){
MailMessage mailNew = new MailMessage();
var smtp = new SmtpClient("SmtpServer")
{
EnableSsl = false,
DeliveryMethod = SmtpDeliveryMethod.Network
};
smtp.Port = 587;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.UseDefaultCredentials = false;
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential("UserName", "password");
smtp.EnableSsl = false;
smtp.Credentials = credentials;
MailAddress mailFrom = new MailAddress("clark#gmail.com");
mailNew.From = mailFrom;
mailNew.To.Add("someone#gmail.com");
mailNew.Subject = Subject;
mailNew.IsBodyHtml = Html;
mailNew.Body = Body;
smtp.Send(mailNew);
return true;
}
I want to add coding for storing the sent mail in sent folder of Outlook.
You will need to create a fake sent item. Note that messages in the Outlook Object Model are created in the unsent state, which cannot be modified.
The only exception is the post item. The following VB script creates a poat item in the Sent Item folder, resets the message class, reopens it as a regular MailItem (which is now in the sent state). Note that you cannot set the sender related properties using OOM alone and you cannot set the sent/received dates.
'create PostItem
set msg = Application.Session.GetDefaultFolder(olFolderSentMail).Items.Add("IPM.Post")
msg.MessageClass = "IPM.Note"
msg.Subject = "fake sent email"
msg.Body = "test"
msg.Save
vEntryId = msg.EntryID
set msg = Nothing 'release the mesage
'and reopen it as MailItem
set msg = Application.Session.GetItemFromID(vEntryId)
'make sure PR_ICON_INDEX is right
msg.PropertyAccessor.SetProperty "http://schemas.microsoft.com/mapi/proptag/0x10800003", -1
set vRecip = msg.Recipients.Add("fakeuser#domain.demo")
vRecip.Resolve
msg.Save
If using Redemption is an option, it lets you set the sent state before the first save (MAPI limitation) and allows to set the sender and date properties correctly:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set msg = Session.GetDefaultFolder(olFolderSentMail).Items.Add("IPM.Note")
msg.Sent = true
msg.Subject = "fake sent email"
msg.Body = "test"
set vRecip = msg.Recipients.Add("fakeuser#domain.demo")
vRecip.Resolve
'dates
msg.SentOn = Now
msg.ReceivedTime = Now
'create fake sender
vSenderEntryID = Session.AddressBook.CreateOneOffEntryID("the sender", "SMTP", "me#domain.demo", true, true)
set vSender = Session.AddressBook.GetAddressEntryFromID(vSenderEntryID)
msg.Sender = vSender
msg.SentOnBehalfOf = vSender
msg.Save

Custom outlook plug in not downloading as expected

I have written a custom code such that when ever an email arrives which has an attachment,it must get downloaded into a shared location, and email arrives daily.
When I open my laptop daily it's working fine if i don't open and if there are continuous mails (with attachments) and it is not getting downloaded for example, when i open my laptop on monday I have 3 mails with attachment (from satu, sunday, monday).
It is not downloading the latest report from monday it is still showing me same report on saturday.
Here is my code..
private void ThisAddIn_Startup(object sender,System.EventArgs e) {
outlookNameSpace=this.Application.GetNamespace("MAPI");
inbox=outlookNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
items=inbox.Items;
items.ItemAdd +=new Outlook.ItemsEvents_ItemAddEventHandler(items_ItemAdd);
}
private void items_ItemAdd(object Item) {
Outlook.Items inboxitems;
const string destinationDirectory=#"\\Service Now\";
Outlook.MailItem newEmail=null;
inboxitems=inbox.Items.Restrict("[Unread] = true");
try {
foreach (object collectionItem in inboxitems) {
newEmail=collectionItem as Outlook.MailItem;
if (newEmail !=null) {
if (newEmail.Attachments.Count > 0) {
for (int i=1; i <= newEmail.Attachments.Count; i++) {
if (newEmail.Attachments[i].FileName.Contains("Logic")) {
// String Des= destinationDirectory.Remove(0, 1);
newEmail.Attachments[i].SaveAsFile(destinationDirectory + newEmail.Attachments[i].FileName);
// MessageBox.Show("Hurry");
}
}
}
}
}
}catch (System.Exception ex) {
MessageBox.Show(""+ex);
}
}
Did you try to debug the code?
I see the following conditions in the code:
inboxitems= inbox.Items.Restrict("[Unread] = true");
and
if (newEmail.Attachments[i].FileName.Contains( "Logic"))
Make sure that emails corresponds to the conditions shown above.
Be aware, the ItemAdd event of the Items class is not fired when a large number of items are added to the folder at once (more than 16).
P.S. Try to check out the MarkForDownload property of Outlook items - an OlRemoteStatus value that determines the status of an item once it is received by a remote user.

Resources