Export Your OPML from Outlook

Lately I have fallen in love with Office programming, but I’m still a complete n00b at it.  I was pilfering through my RSS feeds the other day, and realized I didn’t have a way to export the feeds list as OPML.  Hmm… good time to open Visual Studio and start tinkering.  Here is what I came up with.

Create the Project

To get started, go to the C# node in the New Project window, and you’ll find a sub-node called Office, and another called 2007.  Click on the 2007 node, and create a new Outlook 2007 Add-In project (remember that Outlook 2003 didn’t have RSS support out of the box).

image

That creates a project with a file called ThisAddIn.cs.  Open that file, and you’ll see some code like this already stubbed out.

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;

namespace OutlookAddIn2
{
    public partial class ThisAddIn
    {
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }
        
        #endregion
    }
}

Sweet, you’re halfway there!  Next, we’ll add some using statements. 

 using System.Xml;
using System.Windows.Forms;

Add functions that will add a CommandBar and a CommandButton.  I put them into separate functions here only for readability, you could have put all of this in one big honking method if you wanted to.

         private void AddCommandBar()
        {
            //Add the command bar
            bar = Globals.ThisAddIn.Application.ActiveExplorer().CommandBars.Add(
                "RSS Feeds",
                Office.MsoBarPosition.msoBarTop,
                false,
                true);
            bar.Protection = Office.MsoBarProtection.msoBarNoCustomize;
            bar.Visible = true;
        }

        private void AddCommandButton()
        {
            //Add a command button to the bar
            button = bar.Controls.Add(
                Office.MsoControlType.msoControlButton,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                true) as Office.CommandBarButton;

            button.Caption = "Export OPML";
            button.Click += new Office._CommandBarButtonEvents_ClickEventHandler(button_Click);                        
        }

When our newly created button is clicked, we want to pop open a Save File dialog.  That’s really easy, we just use the good ol’ Windows Forms stuff to do that.

         void button_Click(Office.CommandBarButton Ctrl, ref bool CancelDefault)
        {                        
            //Launch the Save File Dialog
            System.Windows.Forms.SaveFileDialog saveDialog = 
                new System.Windows.Forms.SaveFileDialog();
            saveDialog.Filter = "OPML files|*.opml";
            saveDialog.Title = "Save OPML file";
            saveDialog.ShowDialog();
            if (saveDialog.FileName.Length > 0)
            {
                ExportOPML(saveDialog.FileName);
                System.Windows.Forms.MessageBox.Show("Saved OPML to " + saveDialog.FileName);
            }            
        }

Next is our function to actually export the OPML for our feeds. 

         private void ExportOPML(string fileName)
        {
            XmlWriter writer = XmlWriter.Create(fileName);
            writer.WriteStartDocument();
            writer.WriteStartElement("opml");
            writer.WriteAttributeString("version", "1.0");
                writer.WriteStartElement("head");
                writer.WriteEndElement(); //head
                writer.WriteStartElement("body");
                    ExportRSSFeedList(writer);
                writer.WriteEndElement(); //body
            writer.WriteEndElement(); //opml
            writer.WriteEndDocument();
            writer.Flush();
            writer.Close();
        }

Getting the RSS URL From Outlook

Now that we have the basic structure of our add-in, we need to dig into the RSS feeds themselves in Outlook.  Thankfully, my friend Andrew Coates was kind enough to point me to the following post to show how to get to the RSS feeds.

         private void ExportRSSFeedList(XmlWriter writer)
        {
            // Find the RSS feeds folder
            Outlook.Application app = this.Application;
            Outlook.MAPIFolder folder = app.GetNamespace("MAPI").GetDefaultFolder(
                Outlook.OlDefaultFolders.olFolderRssFeeds);

            EnumRssFeeds(folder, writer);
        }

Finally, we add our custom EnumRssFeeds method.

         private void EnumRssFeeds(Outlook.MAPIFolder parentFolder, XmlWriter writer)
        {
            if (parentFolder != null)
            {

                // Iterate through the sub-folders
                foreach (Outlook.Folder childFolder in parentFolder.Folders)
                {

                    Outlook.StorageItem item = 
                        childFolder.GetStorage("IPM.Sharing.Binding.In",
                            Outlook.OlStorageIdentifierType.olIdentifyByMessageClass);

                    writer.WriteStartElement("outline");
                    writer.WriteAttributeString("text", childFolder.Name);
                    if (item != null && item.Subject != null)
                    {                        
                        writer.WriteAttributeString("xmlUrl", item.Subject);                    
                    }

                    EnumRssFeeds(childFolder, writer);
                    writer.WriteEndElement();
                }                
            }
        }

That’s it!  If you hit F5 and run the project, Outlook will pop open, and your new menu bar and button will appear.  Click on it, and you can export your RSS feeds in Outlook as OPML.

image

I am still trying to reverse the process, I want to figure out how to import OPML and create new RSS subscriptions.  Yeah, I know that Outlook does this already, but it doesn’t honor the structure in the OPML file.  Maybe I can get AC to use Outlook for RSS feeds again.

For More Information

https://social.msdn.microsoft.com/forums/en-US/vsto/thread/de270997-75cd-4dd2-9ff5-e8ca11940437/

Saving Files Using the SaveFileDialog Component

Microsoft Office Outlook Programming Using VSTO 3.0 and C#: Part 1 (shows how to add a toolbar and button)