Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

OutlookをVBAでRSSリーダーにする

VBAによるOutlookのRSSリーダー化

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2005/04/06 00:00

ダウンロード RSS取得マクロ (3.0 KB)

Outlook型RSSリーダーではなく、Outlook VBAを使ってOutlookをRSSリーダーに拡張します。

OutlookでRSSリーダー
OutlookでRSSリーダー

はじめに

 昨今のWebサイトではブログの興盛にともない、RSS配信が当たり前のこととなりました。これにともなって、「RSSリーダー」や「アグリゲーター」と呼ばれるRSSを効率よく収集するためのツールが、出回るようになってきています。これらのソフトウェアのインタフェースで、Outlook的な3ペイン型のウインドウ構成になっているものをよく見かけます。例えば「goo RSSリーダー」です。

 さてここで、RSSリーダーをOutlook風にするよりは、いつも使っているOutlookがRSSリーダーになる方が使いやすいのではないか…とだれもが思うことでしょう。Outlookを常用メーラーとして使用している人であれば、操作感も同じですし、RSSを読むということとメールを読むということが一体化し、情報収集能力もアップしそうな気がします。

Outlook Expressは不可
 この記事の対象は「Outlook Express」ではなくてMicrosoft Officeの「Outlook」のことです。Outlook ExpressにはVBAが利用できないため、この記事は有効ではありません。

対象読者

 VBAを使ったプログラムの経験者を想定しています。

必要な環境

 Microsoft Outlookと、MSXML 4.0 Service Pack 2以上が必要です。XMLの解析に複雑なことはしていないので、MSXML 3.0 Service Pack 5 (SP5)でも大丈夫でしょう。

COMアドインによるOutlookのRSSリーダー化

 OutlookをRSSリーダーにする方法の一つとしては、Outlookの「COMアドイン」を使用するというのがあります。[ツール]→[オプション]→[その他]→[詳細オプション]を選択し、[COMアドイン]をクリックして、そういったRSS収集機能を持つアドイン(プラグイン)を追加することができます。

 COMアドイン型のOutlook用のRSSリーダーとしては以下のものが現在あるようです(他にもあるかもしれませんが未調査)。

VBAで作る?

 RSSの受信は限定的に(自分仕様で)実装するのであれば、プログラマーにとっては1日でできるような簡単な作業です。簡単なだけに「COM」的なちょっと大げさな仕組みに頼らなくても、よいのではないか? 例えばOutlookのVBAでできないのだろうか? という直感が沸いてきます。

 OutlookのVBAがいったい世間では何に使用されているのか、ウイルスの作成くらいしか、思いつきませんが、マジメに使えばメール処理に絡んだ一通りのことは、処理として記述できるようなので、RSSリーダーができそう…な気がします。

.NETでCOMアドイン
 ちなみにCOMアドインも.NETを使えば比較的作りやすいのでそういうアプローチもあるでしょう。

RSS受信処理フロー

 OutlookのVBAは本来はメーラーの処理を自動化するものです。端的に言うと、メールを作成したり、送信したり、といったことを自動的に行なえるわけです。このことを応用して、OutlookをRSSリーダー化するための処理フローとして、とりあえず以下のように定めてみます。

  1. RSSをWebサイトから取得する
  2. 取得したRSSの情報を切り分ける
  3. 切り分けたRSSの各情報を1つのメッセージとして作成(投稿)する
  4. 投稿したメッセージを所定のフォルダに移動する

対象RSS

 対象とするRSSはRSS 1.0限定とします。他のバージョンへの対応は後から各自拡張してください。

RSS受信のためのインタフェース

 RSS受信するためのインタフェースを以下のように決めます。

  1. RSSを受信するフォルダは[個人用フォルダ]以下に作成したメールアイテムを保存可能な任意のフォルダとする。
  2. 受信するRSSのURLはフォルダのプロパティにある[アドレス]に記述しておく。
  3. 受信処理用のメインルーチンはマクロとしてツールバーからクリックで呼び出す。

インタフェースの作成

  1. [個人用フォルダ]を右クリックして[フォルダの作成]を選択。
  2. [名前]を「RSSTest」とする。
  3. 作成したフォルダ「RssTest」を右クリックして[プロパティ]をクリック。
  4. [ホームページ]タブをクリックして「アドレス」に受信したいRSSへのURLを入力します。例えばここでは、@ITの「すべてのフォーラムの新着情報15本」のURLである「http://www.atmarkit.co.jp/rss/rss2dc.xml」というURLを入れておきます。

 以上で、インタフェースの作成は終わりです。

 ちなみに、たまたま、フォルダにURLを書ける欄があったのでこのようなお手軽仕様にしていますが、別に外部のコンフィグファイルにしておいて、それを読むような仕様にしてもいいです。各自自分の方法を考えることが大事です。

準備

 RSSはXML文書として配信されています。受信したXMLファイルを解析するために、無料でMicrosoftより配布されている、MSXMLを利用します。ここでは、現時点での最新版の「4.0」をインストールしておけばよいでしょう。

 また、RSSの仕様については、「RSS -- サイト情報の要約と公開」などがわかりやすいので読んでおくとよいでしょう。もちろん、わからなくても本家の「RDF Site Summary (RSS) 1.0」を読むことも重要です。

 VBAの準備です。[ツール]→[マクロ]→[Visual Basic Editor]をクリックします(または[Alt]+[F11]キー)。Visual Basic Editorが起動したら、プロジェクトエクスプローラから[Project1]を右クリックして[挿入]→[標準モジュール]を選択します。「Module1」が追加されます。ここにコードを記述します。

 今回、XMLの解析にMSXMLを使用するため、プロジェクトにMSXMLへの参照も追加しておきます。[ツール]→[参照設定]で、表示される[参照可能なライブラリファイル]の中から[Microsoft XML, v4.0]にチェックをつけて、[OK]をクリックします。

MAPIフォルダの取得

 現在選択しているフォルダへの参照をActiveExplorer.CurrentFolderによって取得し、そのフォルダからWebViewURLプロパティによりURL情報を取得します。

Dim oRssFolder As MAPIFolder
Dim rssUrl As String

Set oRssFolder = ActiveExplorer.CurrentFolder
rssUrl = oRssFolder.WebViewURL

 ちなみに選択したフォルダは、MAPIFolderというオブジェクトになっています。このオブジェクトはOutlookが扱うさまざまなアイテム(メールや予定表等)をすべて同列に扱うためのフォルダオブジェクトです。MAPIというのはMicrosoftが提唱する、メールを扱うための標準的なAPIです。

XMLの同期読み込み

 URLを取得したら、XMLを同期的に読み込みます。非同期ではないことに注意してください(asyncのデフォルトは「True」(非同期))。「非同期」だと、読み込みが終わる前に次の行が実行されるため、そのための処理をきちんと書いておかないと、エラーになります。「同期」は処理が硬直的ですが、サンプルとしては簡単なので、ここでは同期でいきます。

'RSSデータの取得:非同期OFFにすること
xmlDoc.async = False
If (xmlDoc.Load(rssUrl) = False) Then
    Debug.Print xmlDoc.parseError.reason
    Exit Sub
End If

 エラーが起こったら、とりあえずイミディエイトウインドウに表示するようにしています。

チャンネルノードの処理

 まずチャンネルノードを処理します。XMLのノードの操作は最低限、単数選択ならselectSingleNodeメソッド、複数選択(いわゆるコレクション)の選択ならselectNodesメソッドを使用することを覚えておけばよいでしょう。以降、XMLノード操作の詳細な解説はしません。MSXML SDKのヘルプをご覧ください。

'RDF typeの場合
strxpath = "//channel"

'channel nodeの取得
Set chanNode = xmlDoc.selectSingleNode(strxpath)
chantitle = chanNode.selectSingleNode("title").Text
chanlink = chanNode.selectSingleNode("link").Text
updatestr = chanNode.selectSingleNode("dc:date").Text
chanupdate = ConvertStringToDate(updatestr)

 日付がdc:dateという少し特殊な形式になっているので、ConvertStringToDateというプライベート関数で日付型に変換しています。かなり適当な関数です。

'dc:dateタイプの文字列をDate型に変換(適当に)
Private Function ConvertStringToDate(ByVal strDate) As Date
    'dc:date = 2005-01-13T22:31:00+09:00
    yy = Mid(strDate, 1, 4)
    mm = Mid(strDate, 6, 2)
    dd = Mid(strDate, 9, 2)
    t = Mid(strDate, 12, 8)

    ConvertStringToDate = CDate(yy & "/" & mm & "/" & dd & " " & t)
End Function

アイテムノードの処理

 各アイテム(ニュースの実体)を処理します。以下のようなコードを書きます。

'各Itemの取得
strxpath = "//item"
Set itemNodeList = xmlDoc.selectNodes(strxpath)
   
'日付の新しいものが上になるように逆順にとりだす
Dim i As Long
Dim posttitle As String
Dim postcount As Long
Dim itemlen As Long

itemlen = itemNodeList.Length
For i = itemlen - 1 To 0 Step -1
    Set itemNode = itemNodeList.Item(i)
    
    itemtitle = itemNode.selectSingleNode("title").Text
    itemlink = itemNode.selectSingleNode("link").Text
    itemdesc = itemNode.selectSingleNode("description").Text
    dcdate = itemNode.selectSingleNode("dc:date").Text
    itemupdate = ConvertStringToDate(dcdate)
    
    '件名:同じタイトルを防ぐために日付情報を含める
    posttitle = itemtitle & " [" & dcdate & "]"
    
    '二重登録を防ぐためにタイトルを検索する:同じタイトルは登録しない
    Set findItem = oRssFolder.Items _
        .Find("[件名] = """ & posttitle & """")
    If (findItem Is Nothing) Then
        'Postitemの作成
        Set oPostItem = CreateItem(olPostItem)
        oPostItem.UnRead = True
        oPostItem.Subject = posttitle
        
        strText = posttitle & vbCrLf & _
                  itemlink & vbCrLf & vbCrLf & _
                  itemdesc & vbCrLf
        oPostItem.Body = strText
        
        '直接保存はできない?ので
        'いったん「受信トレイ」にPostしてMoveする
        oPostItem.Post
        oPostItem.Move oRssFolder
    
        postcount = postcount + 1
    End If
Next

日付の新しいものを上に

 自分の好みで、日付の新しいものが件名リストの上に来てほしいので、逆順に取り出しています(もとデータが日付順に並んでいると仮定して)。

二重登録の防止

 二重登録を防ぐために、タイトルを検索して同じメッセージがないかどうか調べてから追加するようにしています。これをしないと同じ件名のものがあった場合、メッセージが重複して作成されます。Outlookはメーラーですから、同じ件名であっても何の問題も無く作成されることに注意です。

メッセージの保存と移動

 メッセージを作成しますが、このときMailIetmオブジェクトではなくPostItemオブジェクトを作成します。MailItemオブジェクトは相手方に何かのメッセージを送信するのが目的なので、今回は、自分当てに投稿するだけで、誰にも送信しませんからPostItemを作成します。PostItemPostメソッドで投稿すると[受信フォルダ]にアイテムが保存されます。これをMoveメソッドで自分のRSS収集用のフォルダに移動させるようにします。

未読の処理

 また、新たに追加したメッセージは未読状態になっていないと、メーラーっぽくありませんので、それの計算を行ないます。これはインタフェースの問題なので、よりシンプルにするのであれば、無くてもよい処理かもしれません。

itemtotal = oRssFolder.Items.Count
'未読にする最初の位置を計算
firstindex = itemtotal - (postcount - 1)
'追加したもののみ未読フラグをつける
For i = itemtotal To firstindex Step -1
    oRssFolder.Items(i).UnRead = True
Next

マクロをツールバーに登録

 完成したルーチンをマクロとして登録します。今回は、仮に「GetRss」というプロシージャ名にしました。登録は以下のようにします。

  1. [ツール]→[ユーザー設定]→[コマンド]の[分類]から[マクロ]を選択。
  2. 右の[コマンド]から[Project1.GetRss]を選択して、ツールバーにドラッグします。

マクロの実行

 RSSを取得したいフォルダを選択した状態で、ツールバーのボタンを押すとフォルダに続々とニュースのリストが降って来ます。

発展

 以上で、OutlookでRSS1.0が読めるようになりました。

 発展系としては、RSS2.0などへも対応するとよいでしょう。またOutlookはHTMLメーラーでもありますから、HTMLとして受信、表示できるようにもできます。具体的には、セキュリティ的な問題がありますが、IFRAMEの表示をONにしておき、IFRAMEsrcに各ニュースのリンク先を記述して、Outlookで表示させれば、即席HTML型RSSリーダーの出来上がりです。

HTML型RSSリーダー的Outlook
HTML型RSSリーダー的Outlook
IFRAMEを表示できるようにセキュリティ設定を変更
IFRAMEを表示できるようにセキュリティ設定を変更

課題

 ポストメッセージを作成すると「差出人」欄がどうしても自分の現在アクティブなアカウント名になります。見栄えがちょっと悪いです(回避方法はあるのでしょうか?)。また、RSSの定期自動取得機能が欲しいところです。VBAだと、力技でできなくもないですが、そこまでやるのならCOMアドインを使ったほうがよいでしょう。

まとめ

 既にあるものを使えば、わずか150行ほどのコードでもRSSリーダーが作れます。「~リーダー」など名前はたいそうですが、たいしたことはしていません。

 また、今回は外部のXMLデータを切り分けて、その情報をOutlookに保存するということのサンプルにもなっています。RSSに限らず、インターネット上のさまざまなリソースをOutlookに保存するときの応用にも使えるでしょう。

  • VBAでOutlookをRSSリーダーにできる。
  • VBAでXMLを処理するときはMSXMLの使用が効率的。
  • メッセージを送信せずに保存するにはPostItemを使う。
  • IFRAMEタグを使えば、URLだけでHTML文書を表現できる。
  • RSSは単なるXML文書。
Outlook Expressならタスクトレイ?
 ちなみに、Outlook Expressで同様のことをしたい場合は、外部アプリケーションからOutlook Expressのメールフォルダを操作することは可能なので、実装するなら、タスクトレイアプリケーションとして実装するとうまく行くかもしれません。

参考資料

  1. MSXML 4.0 SDKドキュメント
  2. RSS -- サイト情報の要約と公開
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5