none
[VSTO]Outlook 2016で返信時の本文の編集について(C#) RRS feed

  • 質問

  • いつも助けていただいて、ありがとうございます。

    以前Outlook2016におけるItemEvents_10_Eventで
    Outlook2016でポップアウトしないOutlook本体のメール編集画面での
    メールアイテムの操作について教えていただきました。

    結果的に、ポップアウトしたメールは
    InspectorsEvents_NewInspectorEventHandlerで
    ポップアウトしないOutlook本体のメール編集画面のメールは
    ItemEvents_10_Eventでメールアイテムを取得して、
    当初の目的だったBCCの編集は期待通り動作していました。

    [質問事項]
    最近になって特定の件名が含まれる場合、本文に特定の文字を自動挿入することになりました。
    ところがItemEvents_10_EventのReply,Forwardイベント発生先でBodyを編集すると、
    メール編集画面にプログラム内で追加した文字列が表示されないばかりか、
    受信トレイなどのメールそのものが編集され(文字列が追加された状態)
    保存されてしまいます。

    どのように操作すればポップアウトしない(Outlook本体のメール編集画面での)
    Reply,Forward時にメール本文に文字列を事前追加することができるのでしょうか。

    いろいろ試しましたが、どうしてもできませんでした。
    とてもどうぞよろしくお願いいたします。

    環境は前回と同じです。
    Visual Studio 2017 + Office 365 Business(Office 2016)

    [試したこと(の一部)]
    ■1
    ItemLoad のイベント後のReply,Forwardイベント発生時に本文を編集していたのを
    ExplorerEvents_10_SelectionChangeEventHandlerでのイベント発生後の
    Reply,Forwardイベントで本文を編集する。

    <結果>
    変わらず。受信トレイなどのメールそのものが編集され保存される。
    もちろんメール編集画面にプログラム内で編集された文字列が表示されない。

    ■2
    項目「■1」のReply,Forwardイベント発生時に、メールアイテムに対して
    mailItem.GetInspector.Activate(); としたあとに本文を編集する。

    <結果>
    メール編集画面がポップアウトしてしまうためそれ以前の問題でした。

    ■3
    Outlook本体のリボンにボタンを追加して、押したときにあらかじめ
    Reply,Forwardイベントで取得したメールアイテムの本文を編集する。

    <結果>
    問題なく本文に指定した文字列が追加できました・・・。
    ※これは期待の動作ではありません。返信,転送,全員に返信のボタンを押し、
    Outlook本体のメール編集画面が表示されるときに、文字列を追加しておきたいのです。

    2019年1月4日 20:47

回答

  • 編集タイミングを遅らせてみるとか

    namespace OutlookAddIn2
    {
        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;
    
        public partial class ThisAddIn
        {
            System.Threading.SynchronizationContext context;
    
            private void ThisAddIn_Startup(object sender, System.EventArgs e)
            {
                //メインスレッドのコンテキストを用意
                context = System.Windows.Forms.WindowsFormsSynchronizationContext.Current;
                if (context == null)
                {
                    context = new System.Threading.SynchronizationContext();
                    System.Windows.Forms.WindowsFormsSynchronizationContext.SetSynchronizationContext(context);
                }
    
                Application.ItemLoad += Application_ItemLoad;
            }
    
            void Application_ItemLoad(object Item)
            {
                Outlook.MailItem mailItem = Item as Outlook.MailItem;
                Outlook.ItemEvents_10_Event mailItem10Events = (Outlook.ItemEvents_10_Event)Item;
                if (mailItem != null && mailItem10Events != null)
                {
                    mailItem10Events.Reply += mailItem10Events_Reply;
                    mailItem10Events.ReplyAll += mailItem10Events_ReplyAll;
                    mailItem10Events.Forward += mailItem10Events_Forward;
    
                    Outlook.ItemEvents_10_UnloadEventHandler unload = null;
                    mailItem10Events.Unload += unload = () =>
                    {
                        mailItem10Events.Reply -= mailItem10Events_Reply;
                        mailItem10Events.ReplyAll -= mailItem10Events_ReplyAll;
                        mailItem10Events.Forward -= mailItem10Events_Forward;
                        mailItem10Events.Unload -= unload;
                    };
                };
            }
    
            void mailItem10Events_Forward(object Forward, ref bool Cancel)
            {
                DelayEdit(Forward);
            }
    
            void mailItem10Events_ReplyAll(object Response, ref bool Cancel)
            {
                DelayEdit(Response);
            }
    
            void mailItem10Events_Reply(object Response, ref bool Cancel)
            {
                DelayEdit(Response);
            }
            void DelayEdit(object Response)
            {
                Outlook.MailItem mailItem = Response as Outlook.MailItem;
                if (mailItem != null)
                {
                    //BeginInvokeと同じこと
                    context.Post((o) => 
                    {//元のイベントを抜けた後に処理が行われる
    
                        //mailItem.Display(false);
    
                        mailItem.BodyFormat = Outlook.OlBodyFormat.olFormatPlain;
                        mailItem.Body = "てすと";
                    }, null);
                }
            }
    
    
            private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
            {
                Application.Inspectors.NewInspector -= Inspectors_NewInspector;
                Application.ItemLoad -= Application_ItemLoad;
            }
    
            #region VSTO で生成されたコード
            private void InternalStartup()
            {
                this.Startup += new System.EventHandler(ThisAddIn_Startup);
                this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
            }
            #endregion
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク よーすけ 2019年1月14日 7:02
    2019年1月5日 6:37

すべての返信

  • 編集タイミングを遅らせてみるとか

    namespace OutlookAddIn2
    {
        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;
    
        public partial class ThisAddIn
        {
            System.Threading.SynchronizationContext context;
    
            private void ThisAddIn_Startup(object sender, System.EventArgs e)
            {
                //メインスレッドのコンテキストを用意
                context = System.Windows.Forms.WindowsFormsSynchronizationContext.Current;
                if (context == null)
                {
                    context = new System.Threading.SynchronizationContext();
                    System.Windows.Forms.WindowsFormsSynchronizationContext.SetSynchronizationContext(context);
                }
    
                Application.ItemLoad += Application_ItemLoad;
            }
    
            void Application_ItemLoad(object Item)
            {
                Outlook.MailItem mailItem = Item as Outlook.MailItem;
                Outlook.ItemEvents_10_Event mailItem10Events = (Outlook.ItemEvents_10_Event)Item;
                if (mailItem != null && mailItem10Events != null)
                {
                    mailItem10Events.Reply += mailItem10Events_Reply;
                    mailItem10Events.ReplyAll += mailItem10Events_ReplyAll;
                    mailItem10Events.Forward += mailItem10Events_Forward;
    
                    Outlook.ItemEvents_10_UnloadEventHandler unload = null;
                    mailItem10Events.Unload += unload = () =>
                    {
                        mailItem10Events.Reply -= mailItem10Events_Reply;
                        mailItem10Events.ReplyAll -= mailItem10Events_ReplyAll;
                        mailItem10Events.Forward -= mailItem10Events_Forward;
                        mailItem10Events.Unload -= unload;
                    };
                };
            }
    
            void mailItem10Events_Forward(object Forward, ref bool Cancel)
            {
                DelayEdit(Forward);
            }
    
            void mailItem10Events_ReplyAll(object Response, ref bool Cancel)
            {
                DelayEdit(Response);
            }
    
            void mailItem10Events_Reply(object Response, ref bool Cancel)
            {
                DelayEdit(Response);
            }
            void DelayEdit(object Response)
            {
                Outlook.MailItem mailItem = Response as Outlook.MailItem;
                if (mailItem != null)
                {
                    //BeginInvokeと同じこと
                    context.Post((o) => 
                    {//元のイベントを抜けた後に処理が行われる
    
                        //mailItem.Display(false);
    
                        mailItem.BodyFormat = Outlook.OlBodyFormat.olFormatPlain;
                        mailItem.Body = "てすと";
                    }, null);
                }
            }
    
    
            private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
            {
                Application.Inspectors.NewInspector -= Inspectors_NewInspector;
                Application.ItemLoad -= Application_ItemLoad;
            }
    
            #region VSTO で生成されたコード
            private void InternalStartup()
            {
                this.Startup += new System.EventHandler(ThisAddIn_Startup);
                this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
            }
            #endregion
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク よーすけ 2019年1月14日 7:02
    2019年1月5日 6:37
  • gekka様

    早急なご回答をありがとうございました。
    また、返信が遅くなり申し訳ございませんでした。

    期待通りの動作にすることができました。
    gekka様様のご回答を「回答としてマーク」させていただきました。
    本当にとても助かりました。

    SynchronizationContextについては、概念すらなく大変勉強になりました。

    OutlookのVSTOのメールアイテムに本文を編集可能なタイミングのイベントが
    あるはずだといろいろ探していたりもしておりました。

    [補足]

    Outlookでの書式設定がテキストの場合のみの検証結果となりますが、
    テキスト形式のメールを返信する場合などにOffice 365 Business(Office 2016)によって
    自動挿入されるPrefix TEXT?(Prefix HEADER?)※は私が作成しているOutlookのVSTOアドインでは
    「BodyFormat」を明示的に指定すると挿入されませんでした。ので、コメントアウトしています。

    ※Prefix TEXT?(Prefix HEADER?)の例
    -----Original Message-----
    From: a1234@domain.jp
    Sent: Monday, January 14, 2019 2:32 PM
    To: a1234@domain.jp
    Subject: テストメールです


    2019年1月14日 7:09