I'm working on an Outlook Add-In that can work in one of two ways, depending on a user's choice - it can process selected emails, or alternatively, process all emails in the selected folder. I've gotten the first part working, but the second part is giving me trouble, possibly because I'm just adapting the code from the first part incorrectly. I believe the trouble comes down to grabbing the currently selected folder properly in a C# Outlook add-in. I'm using .NET 3.5 and Outlook 2007, by the way.
First, the email code - if a user selects one or more emails in their inbox, and runs my add-in with the "selected emails" option, the following code is run (and works fine!):
public static void processSelectedEmails(Outlook.Explorer explorer)
{
//Run through every selected email
for (int i = 1; i <= explorer.Selection.Count; i++)
//alternatively, foreach (Object selectedObject in explorer.Selection)
{
Object selectedObject = explorer.Selection[i];
if (!(selectedObject is Outlook.Folder))
{
string errorMessage = "At least one of the items you have selected is not an email.";
//Code for displaying the error
return;
}
else
Outlook.MailItem email = (selectedObject as Outlook.MailItem);
//Do something with current email
}
}
I've tried to adapt this code to do something else if a user goes to the Navigation Pane (on the left by default) in Outlook, selects a folder or subfolder (perhaps Inbox, Sent Items, or another folder they've created). The user can then choose the "process selected folder" option in my Add-In, which will do essentially the same thing as the code above, but process all of the email inside the selected folder. I have set it to only work if the user has selected a single folder.
public static void processFolder(Outlook.Explorer explorer)
{
//Assuming they have selected only one item
if (explorer.Selection.Count == 1)
{
//Make sure that that selected item is a folder
Object selectedObject = explorer.Selection[1];
if (!(selectedObject is Outlook.Folder))
{
string errorMessage = "The item you have selected is not a folder.";
//Code for displaying the error
return;
}
//Code for running through every email in that folder
}
}
I have not yet written the code to actually run through all of the emails in the selected folder, because my code never gets past the if (!(selectedObject is Outlook.Folder)). Even if the most recently selected item is your Inbox, I receive the error I have programmed in at that point. Perhaps I am misusing the explorer.Selection thing? Any help would be much appreciated.
This may be important to answering my question - the add-in has a field called 'explorer', which is generated on startup: explorer = this.Application.ActiveExplorer. This is the 'explorer' that is passed to my functions so that they can know what is selected. As I said, this works fine for selected emails, but does not work for selected folders. Any insight would be greatly appreciated!
Edit 1: It appears that this question is basically a duplicate of Get all mails in outlook from a specific folder, but it has no answers.
Edit 2: I've been doing further research, it appears that I can get virtually the same functionality (but with an additional step unfortunately) by creating a popup to select a folder using the Application.Session.PickFolder() method. Is there any way to do it based on the currently selected folder, instead of forcing the user to pick a new folder?
Edit 3: I have modified the code found here: http://msdn.microsoft.com/en-us/library/ms268994(v=vs.80).aspx to further show what is not working properly for me:
public static void processFolder(Outlook.Explorer explorer)
{
string message;
if (explorer.Selection.Count > 0)
{
Object selObject = explorer.Selection[1];
if (selObject is Outlook.MailItem)
{
message = "The item is an e-mail";
}
else if (selObject is Outlook.Folder)
{
message = "The item is a folder";
}
else
{
message = "No idea what the item is!";
}
Console.WriteLine(Message);
return;
}
}
Whether I select a message, or go to the Navigation Pane and select a folder, I receive the message "This item is an e-mail".
Explorer.Selection is for Items only (MailItem, AppointmentItem, etc.) - not Folders. To get access to the currently selected Folder you would need Explorer.CurrentFolder.
Folder.Items would provide you access to all the Items in a given Folder.
Related
When I iterate through all Outlook folders (in a C# Add-In) I see folder names like:
Yammer Root
Sync Issues
Subscriptions
These folders are not visible in Outlook. I like to check in my code if the folder is visible or not but I don't find a property like Hidden or Visible.
MAPIFolder folder has properties like:
folder.DefaultItemType
folder.Name
but not hidden.
How can I find out in my c# Add-In if folders are hidden or not?
You will need to read the PR_ATTR_HIDDEN MAPI property (DASL name http://schemas.microsoft.com/mapi/proptag/0x10F4000B). You can read it using MAPIFolder.PropertyAccessor.GetProperty.
You can see that (and other) property using OutlookSpy (I am its author) - click IMAPIFolder button.
At least on my machine I never retrieved a value for PR_ATTR_HIDDEN for all folders. I could not find out the reason although in OutlookSpy the value is true for the hidden folders.
Code:
var rootFolder = outlook.Session.DefaultStore.GetRootFolder();
foreach (Folder folder in rootFolder.Folders)
{
try
{
bool isHidden = folder.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x10F4000B");
// never reach this line
}
catch (System.Exception ex)
{
// always exception: value is not available
}
}
My workaround: If you want to retrieve the folders as they are displayed in Outlook you can use PR_CONTAINER_CLASS_W and compare it with IPF.Note or IPF.Imap.
Sample:
const string PR_CONTAINER_CLASS_W = "http://schemas.microsoft.com/mapi/proptag/0x3613001F";
string containerClass = folder.PropertyAccessor.GetProperty(PR_CONTAINER_CLASS_W);
bool isVisible = string.Equals(containerClass, "IPF.Note")|| string.Equals(containerClass, "IPF.Imap");
I want to be able to access the auto-complete address list that appears when typing into either the TO,CC or BCC lines within an email. I wish to be able to extract this data similarly to how I access other address lists within Outlook.
Would anyone be able to confirm if this is possible and if so how I could go about doing it.
This is currently how I'm extracting email addresses various other address lists.
foreach (Outlook.AddressEntry item in addressList.AddressEntries)
{
using (item.ComDisposable())
{
switch (item.AddressEntryUserType)
{
case Outlook.OlAddressEntryUserType.olExchangeUserAddressEntry:
case Outlook.OlAddressEntryUserType.olExchangeRemoteUserAddressEntry:
var exUser = item.GetExchangeUser();
Debug.WriteLine(exUser.PrimarySmtpAddress, "_GetOutlookContacts");
yield return new EGContact(exUser.Name, exUser.PrimarySmtpAddress, item.ID);
break;
case Outlook.OlAddressEntryUserType.olOutlookContactAddressEntry:
var contact = item.GetContact();
yield return new EGContact(contact.FullName, contact.Email1Address, item.ID);
break;
case Outlook.OlAddressEntryUserType.olExchangeDistributionListAddressEntry:
break;
default:
break;
}
}
}
Autocomplete stream is stored as a hidden (associated) message with the message class of "IPM.Configuration.Autocomplete" in the Inbox folder. You can see the data in OutlookSpy (I am its author): go to the Inbox folder, click IMAPIFolder button on the OutlookSpy ribbon, go to the "Associated Contents" tab, locate a message with PR_MESSAGE_CLASS == "IPM.Configuration.Autocomplete", select the PR_ROAMING_BINARYSTREAM property to see its contents.
You can open that message using the Outlook Object Model (MAPIFolder.GetStorage("IPM.Configuration.Autocomplete", OlStorageIdentifierType.olIdentifyByMessageClass), read the property using PropertyAccessor.GetProperty, then parse it. Note that large autocomplete streams cannot be opened using PropertyAccessor.
If using Redemption an option (I am also its author), it exposes autocomplete as the RDONicknames collection:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set Nicknames = Session.GetNicknames
for each NickName in NickNames
Debug.Print NickName.Name & " - " & NickName.SmtpAddress
next
In an earlier version of Outlook, this information was stored in local .NK2 files. In Outlook 2010 and up, this information is stored in your mailbox (AutoComplete Stream). See Clearing AutoComplete and other Recipient Caches for more information.
You can use the Recipients collection (see the corresponding property of the MailItem class) for accessing the data entered to the To, Cc or Bcc fields.
I have a task which i need to create a program that converts outlook email to pdf.
this is my code
Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
NameSpace outlookNs = app.GetNamespace("MAPI");
MAPIFolder rootFolder = outlookNs.Stores["Blah"].GetRootFolder();
List<MailItem> mailItems = new List<MailItem>();
Folders subFolders = rootFolder.Folders;
foreach (Folder folder in subFolders)
{
if (folder.Name == "Inbox")
{
Items items = folder.Items;
foreach (object item in items)
{
if (item is MailItem)
{
MailItem mailItem = item as MailItem;
string fileName = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "New folder", mailItem.EntryID + mailItem.SenderName.Replace("/", "") + ".msg");
mailItem.SaveAs(fileName, Microsoft.Office.Interop.Outlook.OlSaveAsType.olMSG);
}
}
}
}
the code is working but the outlook contains thousands of email. The outlook prompt a message every 10 minutes similar to the screenshot below
is there a way to avoid getting the message? Programatically or a setting will do?
Basically, it's not related to the programming instead of it's related the outlook security settings.
For every version of outlook you can find the settings for this pop-up just follow the instruction on this blog.
You can do a setting in your out look.
Mine is outlook 2013.
File->options : a window opens
In the window select Trust Center
You can see a button Trust center Settings
Options in window changes. Select Programmatic access
UnCheck the radio button Never warn me about suspicious activity (not recommended)
Through program, you can change below registry settings:
Go to "HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\15.0\outlook\security"
Change below settings programatically:
PromptSimpleMAPISend -- 2
PromptSimpleMAPINameResolve -- 2
PromptSimpleMAPIOpenMessage -- 2
By default when outlook is installed, the above values comes with zero value. What I do in my program is, I turn them to "2" programatically just before sending the email and turn them back to zero later point of time.
Background
We have a custom developed installed .WSP on a SharePoint 2007 environment and have been in the process of upgrading to 2010. With the upgrade the custom event trigger no longer worked so trying to update and make it work in 2010. But I am running into one issue. Original developers no longer here and I've been the lucky one to have to figure this one out without much of a background with SP Dev.
Goal
When a new list item is created trigger event. Within event, create a shared folder using Item Name and return url, create a wiki-page using item name and include shared document link and return url to wiki page. Part three is update newly created list item with the New Folder url and Wiki Page URL.
Issue
I've gotten the first two parts working but so far have been unable to update the newly created list item with the new Links. I'm able to get the links. I've tried all the basic stuff for updating the list that I have been able to find online with no luck. Nothing to complicated(or so I think). But code is included below. VS is not installed on the server so unable to run debug mode, I don't have direct access to the server. When you create the item there are no client/user side error. Haven't been able to find a log file that has any, that is if it collects errors if the script were to fail out.
Initiation of the Event
public class CreateWikiAndFolder : Microsoft.SharePoint.SPItemEventReceiver
{
public override void ItemAdded(SPItemEventProperties properties)
{
try
{
//this.DisableEventFiring();
base.EventFiringEnabled = false;
string sUrlOfWikiPage = string.Empty;
string sUrlOfNewFolder = string.Empty;
string sSubsiteRUL = string.Empty;
string sCurrentItemTitle = properties.ListItem["Title"].ToString();
string sWikiListName = "TR Wikis";
string sDocLibName = "Shared Documents";
string sTRListID = "TR Status";
if (sTRListID.ToUpper().Equals(properties.ListTitle.ToString().ToUpper()))
{
//Create the Folder
sUrlOfNewFolder = CreateFolder(properties.ListItem.Web, sDocLibName, sCurrentItemTitle);
//Create the Wiki
string ItemDispFormUrl = String.Concat(properties.ListItem.Web.Url, "/", properties.ListItem.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url, "?ID=", properties.ListItem.ID.ToString());
sUrlOfWikiPage = CreateWiki(properties.ListItem.Web, sWikiListName, sCurrentItemTitle, ItemDispFormUrl, sUrlOfNewFolder);
//Update the current TR Item
//Have tried. properties.ListItem["WikiURL"] = sUrlOfWikiPage + ", " + "Wiki";
SPListItem myListItem = properties.ListItem;
SPFieldUrlValue shareFolderURLValue = new SPFieldUrlValue();
shareFolderURLValue.Description = "Shared Folder";
shareFolderURLValue.Url = sUrlOfNewFolder ;
myListItem["SharedFolder"] = shareFolderURLValue;
//I've tried each one separate and together to no luck
myListItem.UpdateOverwriteVersion();
myListItem.Update();
//properties.ListItem.UpdateOverwriteVersion();
}
base.EventFiringEnabled = true;
}
}
}
Note that this is the last thing needed to be figured out for our upgrade.
Got it working. I did both of these at the same time so I'm not sure if it was the combination of both or only one of the items. But one I removed the myListItem.UpdateOverwriteVersion(); line and surrounded the item updated with web.AllowUnsafeUpdates being set to true before and then back to false afterwards.
Also as a note to others, you need to save the properties.ListItem to its own SPListItem which you then update versus trying to manipulate the values at the properties.ListItem["Attribute"], and then update the properties.ListItem.Update. SharePoint doesn't allow the latter option so you have to save to an independent SPListItem, and then modify and update that one. This might not be the best SharePoint lingo, but that is what needs to be done.
following this link - change outlook MailItem icon
I managed to change my inbox icons.
Here's what I did step by step.
1) Created a custom message class for new mail that arrives from the Internet
The class is IPM.Note.Internet
Outlook.NameSpace outlookNameSpace;
Outlook.MAPIFolder inbox;
Outlook.Items items;
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);
}
void items_ItemAdd(object Item)
{
Outlook.MailItem mailitem = (Outlook.MailItem)Item;
String EmailHeader = mailitem.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001E");
if (Item != null && EmailHeader.Contains("Look for a string in the headers here that we set for incomming mail") == true)
{
if (mailitem.MessageClass == "IPM.Note")
{
mailitem.MessageClass = "IPM.Note.Internet";
mailitem.Save();
}
}
}
2) Created a replacement Outlook Form Region matching the MessageClass. In this case I used IPM.Note.Internet
3) Assign the Icons in the Properties Pane of the Form Region Designer.
4) Debugged project and the next message that arrived from the internet was stamped with my custom icons after the message class was updated.
My issue now is that I can't preview or open the messages where I changed the message class. Similar to this post that's unanswered - Change Inbox-icons in Outlook at runtime
I think the issue is that my replacement Outlook Form Region is blank so the message is not able to be previewed.
If this is true than here's my question. What is the best way to export the standard IPM.Note message class template into visual Studio. I thing I need to overwrite my IPM.Note.Internet Outlook Form Region design.
There is an option when creating an Outlook Form Region-
To import an ".OFS" file. I was attempting to figure out how to export the file from the Outlook 2010 Client (Developer Tools) but I can't find a way to save the templates to that specific format. I can save to OFT (office template) but not .OFS
Thanks in advance for any help!
Rather then adding a form region and changing the message class I just ended up adding the PR_ICON_INDEX property and setting it's value. As outlined here in option #2 by Dmitry Link
There are many icons to choose from here. I couldn't locate a list with the integer values so I just entered random numbers for the PR_ICON_INDEX property in Outlook Spy changing the value till located the icon I wanted. There are many icons to choose from. Many from the 600-700 and 1000 and up range.
Here's the line I used to set the PR_ICON_INDEX property on the message-
mailitem.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x10800003", 4); // change the 4 to something like 600,601...etc to experiment