Outlook MessageIdTools Addin
以前から取り組んでいる、OutlookでメッセージIDを使って検索する、についてOfficeアドインを作ってみました。 懸念だったパフォーマンスも問題なさそう。
OutlookMessageIdToolsAddin
このアドインで出きることは、こんな感じです。
- メッセージIDやタイトルを付けてメールをクリップボードにコピーできる。コピーのパターン(テンプレート)は3つまで定義可能。
- メッセージIDを使ってメールを検索できる。
Outlook 2010以上で動くと思います。
ダウンロード
OfficeアドインはClickOnceがおすすめよっとMicrosoftさんはおっしゃっていますが、 わかりやすいmsiにしておきました。
オフラインでもインストールしやすいですしね。
あとでChocolateyのパッケージも作っておこうかと思います。
使われ方想定
こんな使い方を想定しています。
1. BTS等にメールを貼り付ける際にメッセージIDを付けておく
GitHubやRedmine等のBTSにメールでのやり取りを載せる際、単にメールをコピーするだけでは、後になって読み返したときに 情報が足りないことがあります。 そんな時、メッセージIDを付けておくとOutlook内をメッセージIDで検索し、BTSに貼られたメールの前後のメールにたどり着くことができます。
MessageID: <al7qarzSgNdG4q.5.1430975248.16337.forcast@news>
Received: 2015/05/07 20:14:55
Sender: Sofmap.com (commaster@sofmap.com)
Subject: 日曜日の昼はゲームやホビーがもっとオトク!「日曜昼市」大好評開催中!!【SofmapNews店舗】
*****━━━━━━━━━━━━━━━━━━━━━━━━━ <2015-5-7>
。・゜・☆。ソ フ マ ッ プ ニ ュ ー ス 店 舗 ゜。・。・゜・。゜。
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*****
整形済みテキストの書式(GitHubは```、Redmineは<pre>)をあらかじめテンプレートにしておくと便利です。
2. メッセージIDを使ってメールの参照を表す
「○月○日のメール」といった言い方ではなく、「メッセージIDが~のメール」という言い方をすることで すぐに、指定したメールを特定できます。 テンプレートをMessageIDのみにしておくと、簡単にコピーできますね。
Officeアドインを作ってみて
C#で書けるので意外と簡単でした。
ポイントは、
Officeアドインはこの辺を参考に。
Office AddIn の作り方 〜開発編〜 - Natural Software
VSTOでExcel 2007のカスタムリボンを作成する (1/3):CodeZine
インストーラのつくり方はこの辺を参考にしました。
Office 2007 アプリケーションの Windows Installer による配布方法 (VSTO v3 編) - 松崎 剛 Blog - Site Home - MSDN Blogs
deployment - How do you use WiX to deploy VSTO 3.0 addins? - Stack Overflow
Outlook2013でMessageIdで検索する サブフォルダ対応
以前の記事でOutlook 2013 でMessage IDで検索する方法を書きましたが、 サブフォルダを含めた検索に対応できていませんでした。
http://banban525.hatenadiary.jp/entry/2015/03/27/092824
調べてみても良い方法はどうも見つからず、マクロかアドインになりそうな感じですね。 まずは実装の前に実現性の調査を。
ベタにアドオン内で検索する
ここに検索方法が書いていました。
Searching emails from an Outlook add-in | TaskConnect - Outlook add-in for Team Foundation Server
要するにフォルダ毎にFind("~0x1035001E=***")で探すんですね。
サブフォルダまで自動で探してくれよと思いますが、検索はフォルダ単位なんですね。
メリットは検索まわりが自前のコードで書けるので柔軟性があること。
心配なのはパフォーマンス。
マクロでユーザ定義フィールドに入れる
Outlookにはユーザ定義フィールドというメッセージ毎にテキストフィールド等が増やせる仕組みがあるようです。
またメール受信時に処理するマクロやアドインも作れるそうで、 受信時にユーザ定義フィールドにメッセージIDを入れておけば検索できます。 検索は高度な検索からユーザ定義フィールドを指定すればOK。 サブフォルダも検索できます。
ただ、ユーザ定義フィールドはフォルダ毎なんですよね。 全てのフォルダに対して同じユーザ定義フィールドを作らないといけないみたい。
Outlookさん、どんだけフォルダの独立性が高いんだよ
また、普通の検索ではユーザ定義フィールドはヒットしません。 メール一覧の上にある検索フィールドで検索できるのはタイトルと本文くらいのようですね。 高度な検索を設定するのがわりと面倒です。
メリットはOutlookの検索が使える点。
マクロでタイトルにメッセージIDを付けちゃう
上と同じように受信時のマクロやアドインを使います。
メッセージIDをユーザ定義フィールドではなく、タイトルの後ろにつけてしまうという禁じ手です。
これならメール一覧の上のクイック検索(正式名称は知らない)でもヒットします。 サブフォルダにも対応できるし、ユーザ定義フィールドを作る必要もありません。
割といいアイデアだと思うのですが、タイトルや本文はメールのメインコンテンツであり、 マクロやアドインで加工するのはアウトな気がするんですよね・・・。
間違って文字化けさせたり、消してしまったら目も当てらない。
メリットはOutlookの検索機能、特にクイック検索が使えること。 デメリットは、なんか気持ち悪いこと。
どれにするの?
とりあえず、下の順で作ってみるつもりです。
- ベタにアドオン内で検索する
- マクロでタイトルにメッセージIDを付けちゃう
- マクロでユーザ定義フィールドに入れる
多言語アプリツールキットをWindowsフォームで試してみた
前回の記事で多言語アプリツールキットがWindowsフォームに対応していると書いたので、使用した感じを少々。 Visual Studio 2013です。
WPFは練度が足りないので、後回し(たぶんやりません)。
操作手順
まず、アセンブリ情報でニュートラル言語を設定。「日本語」にすべしという記事があるけど、なんか気持ち悪いので「英語」で。
適当にボタンを配置して・・・
おもむろに、ツール-多言語アプリツールキットの有効化(少し前はこれが出来なかったそうですね)。
すると、*.xlfファイルという見慣れないファイルができます。
翻訳言語の追加、で日本語(日本)と英語を選択すると、
言語に対応したxlfファイルができます。
この時点ではなぜかxlfファイルが空なので、Windowsフォームのデザイナを開いて、FormのLanguageを日本語に設定。 よくあるWindowsフォームの多言語の手順ですね。 (ここでもしかするとビルドが必要かも)
xlfファイルをダブルクリックすると、翻訳専用のウィンドウが開きます。先ほど作ったボタンのリソースが登録されていますね。この時点では英語のままです。
そこで、xlfファイルを選んで、機械翻訳の生成を実行すると・・・
日本語化されました!
このプロジェクトをビルドして、日本語環境で実行すると、翻訳されたリソースで表示されます。[○○]の形はいまいちですけど、翻訳エディタで編集すればOKですね。
感想など
どうやって実現しているのかなぁと思いましたが、Windowsフォームからリソースを抽出->xlf形式で保存->カスタムツール(XliffResxGenerator)でresxファイルを生成、としているようですね。 結局はresx形式なので、出力されるアセンブリは同じなんでしょう。 逆に、今までできていたWindowsフォームの子供のresxは作られないようなので、デフォルトの機能を置き換える何かがあるのだと思います。
WindowsのUIってある程度同じような用語が並ぶことがあるので、機械翻訳があるのはうれしいですね。 ただ、翻訳用のエディタは、翻訳作業を意識して文字リソースごとにレビュー済み等のステートを持たせてるようですが、 うまく使えば便利なんでしょうが、私の現状では使うイメージがないです。
また、Visual StudioにおけるWindowsフォームの多言語対応の機能は割と優秀なのでなかなかやめられないです。
逆にWPFは多言語対応が弱いので、そちらでうまく使えるかどうかが気になりますね。
あと、画面以外のリソースについても同じように翻訳ができます。 この場合は、resxにリソースを追加してビルドするだけで対応言語すべてのxlfファイルにリソースが追加されるので 通常のresxだけより便利かと思います。
xlfって何?
XLIFF形式という、翻訳用のXMLファイルのようですね。
Visual StudioのXMLエディタで開けば中を見ることができます。
割と単純な構造のようなので既存のresxから移行する際は、コンバートすればいけそう。 多言語アプリツールキットでは、スキーマはインストールされないようなので、それは少し残念です。
多言語アプリツールキットがWindowsフォームとWPFに対応してた
多言語アプリツールキット、というものがあります。 日本語の情報では、この辺で説明されています。
WinRT/Metro TIPS:多言語化対応を楽に行うには?[Win 8] - @IT
Visual Studio 2013向けの多言語アプリツールキット - 酢ろぐ!
(公式) 多言語アプリ ツールキット - Windows アプリ開発
ブログの情報ではWindowsストアアプリとWindowsPhoneアプリのみとなっていますが、 公式を見ると"デスクトップ アプリのローカライズ ワークフローを効率化します"とあります。
実際にインストールしてみると、WindowsフォームとWPFにも対応しているようです。
まだ、少ししか使っていませんが、使用感などは次の記事で書こうかと思います。
Outlook 2013でメッセージIDで検索する
背景
ですよね?
ここ数年、プライベートも仕事もThunderBirdだったんですが、 会社の方でOffice 365の導入が決まり、 Outlookを使うことになりました。
Outlookと言えば、Windowsセットアップ後真っ先に削除するアプリ、Officeインストール時にフルインストールを選ばない理由、で有名なOutlookです。
まあ、しがないサラリーマンとしては会社の決定に従わないといけません。 幸いThunderBirdをそこまで使い倒している訳ではないので機能的には遜色なさそうです。
メールの自動振り分けもできそうですし、ThunderBirdからのデータのコンバートもできそう。
ただ、見つけられなかったのがメッセージIDを使った検索です。
メッセージIDって便利
メッセージIDはメール1通を特定するためのIDのようで、メールサーバーで割り当てられるようです。
例えばこんな会話よくします。
「そんなメール来てた?」
「○月○日の△さんのメールで・・」
「スレッド表示にしてるから日付じゃ見つけられん、検索キーワードない?」
メッセージIDがあると
「そんなメール来てた?」
「来てたよ、xxxx@xxxx(IMで送信っと)」
「どれどれ・・・、あった!見逃してたよー。」
てな感じになります。
あと、メールをBTSなど別の場所に貼り付けるときもメッセージIDを付けておくと前後のメールを調べ直すときに便利です。
Outlook 2013でのメッセージIDを表示
Outlook 2013でもメッセージIDを表示させることはできます。 メールを開いてファイル-プロパティ。
インターネットヘッダーの欄に「Message-ID」の項目に表示されます。
メッセージIDを使って検索
メッセージIDをフィルタに入れても検索できません。 詳細検索にもヘッダーの項目はありません。
結論から言うとビューの設定でSQL検索して検索します。
ビューの設定を開いて
ビューの詳細設定画面で「フィルター」を選択
SQLタブを開いて
"http://schemas.microsoft.com/mapi/proptag/0x1035001E" = '(メッセージID)'
と打ち込みます。
これでメッセージIDが一致するメールだけがフィルタされます。 毎回ビューの設定をするのは面倒ですが、私は一旦ビューを記憶させておいて SQLを書き換えています。
0x1035001Eってなに?
よくわかりません。 見つけたのがこのページでOutlookのAddinでメッセージIDを検索する方法を説明しているようです。 Searching emails from an Outlook add-in | TaskConnect - Outlook add-in for Team Foundation Server
たぶんですが、Outlookの裏にはDBがあって、メッセージIDは0x1035001Eうんぬんの列に格納されているのではないかと思っています。
C#のImmutable型のチェック
前回の記事でImmutableな型をチェックできないかという話をしました。
ということで、軽く作ってみました。 前回の記事のすべてのフィールドがreadonlyのパターンです。 3時間くらいのやっつけ作業ですが。
banban525/ImmutableChecker · GitHub
ホワイトリストを外部設定にすべきなのとRoslynを使ったprivate setterパターンのチェックが 次のステップの予定。(今から着手するわけではない)
頑固な方がモテるのか?
最近、状態を持たない設計手法をよく耳にします。
- 関数型言語
- DDDのバリューオブジェクト
- .NETのImmutableCollection
これからの時代は不変な型、Immutable型が重要なのでしょう。
ようするに、態度がコロコロ変わる男はモテなくて、一度決めたら突っ走れってことですね。
ということで、我らのC#さんでImmutable型を作るにはどうすればいいのか考えてみます。
public get/private setなプロパティがありフィールドを変更するメソッドがないのクラス
ようするにこんな型です。
public class FakeImmutableType
{
public FakeImmutableType(int no)
{
No = no;
}
public int No{ get; private set; }
}
コンストラクタのみでフィールドは初期化され、それ以降はgetのみ可能です。 もちろん、フィールド/プロパティの型もImmutableである必要があります。 (なので、配列はアウト)
この方法のメリットは、後述するパターンに比べコード量が少ないこと。
すべてのフィールドがreadonlyな型
こんな型です。
public class ImmutableType
{
private readonly int _no;
public ImmutableType(int no)
{
_no = no;
}
public int No
{
get { return _no; }
}
}
前者のパターンと比べるとコード量は増えますが、 言語仕様としてコンストラクタ以外での書き換えを禁止していますから、 クラスがImmutable型であることを明確に表現できます。
また、うっかりフィールドを書き換えるメソッドを作る心配がありません。
ただし、フィールド型がImmutableであることという前提は変わりません。
あと、次のC# 6.0では次のように書けるように簡素に書けるそうです。
public class ImmutableType
{
public ImmutableType(int no)
{
No = no;
}
public int No { get; }
}
Immutableな型であることを宣言する
2つのパターンをあげましたが、どちらの場合もフィールド型がImmutableである必要があります。 注意すればいいだけなのですが、これから使おうとする型がImmutableな型なのかどうかが知りたくなります。 特に標準クラスは何となくわかりますが、独自クラスの場合は目印が欲しくなります。
私がよく使う手はこんな感じで、[Immutable]属性を作って表現します。
public class ImmubtaleAttribute : Attribute
{
}
[Immutable]
public class ImmutableType
{
Visual Studioのインテリセンスには出せませんが、定義を参照すればすぐにわかります。
Immutableであることをチェックする
さてさて、Immutableであることを宣言すると、今度は本当にそうなのかチェックしたくなります。 誤ってImmutableでない型をフィールドにしてしまったり、public setなプロパティを作ってしまったり、が起こりえます。 1人で開発するなら気を付けるだけですが、チーム開発となるとそうもいきません。
「すべてのフィールドがreadonlyな型」のパターンならチェックはこんな感じですね。
- [Immutable]属性がつけられている型について以下の制約を満たすこと
- すべてのフィールドがreadonlyである
- すべてのフィールド型がImmutable型である
完璧には無理ですが、Immutable型のホワイトリストを持てば、リフレクションで割と簡単に実現できそうです。 ちょいと作ってみようと思います。
ただ、もう1つのパターンは、「メソッドの中でフィールドを書き換えていないこと」という制約が必要ですので これはちょっと難しいですね。 out, refあたりを無視すれば、Roslynを使ってできるかもしれません。 気が向けば作ってみます。