C# で Outlook の予定表を取得する



はじめに

Outlookからスケジュール情報を取得しないといけない状況になったので簡単に取得できるソースコードを提供できればと思い記載いたします。
例外処理などをまったく行っていないので各自で実装いただければと思います。

また、本サンプルコードは「NetOffice」ライブラリを使用していますがOutlookのComDLLを使用した場合でも基本的には同じソースコードで動くと思いますが確認していないのでご自由にお使いください。

前提条件

・MS Office Outlookがインストールされている事。
・Visual Studio のある程度のバージョンがインストールされている事。

NetOfficeとは

Microsoft Office製品にアクセスするための.NETラッパーアセンブリのようで、Officeのバージョンに関係なく簡単にコードが書けるとのこと

開発時にOfficeのバージョン指定でDLLを参照しますが、これを使うとバージョンの依存部分を吸収してくれて、開発・運用で別々のオフィスでも可能な限り実行できるのかなと思います。(未検証

Nugetで取得

Nugetパッケージ管理コンソールで以下を実行します。

PM> Install-Package NetOffice.Outlook

ソースコード

VisualStudioに以下、2つのソースコードを追加します。

  • OutlookManager.cs
    • Outlookのスケジュールを取得するための管理クラス
  • ScheduleItem.cs
    • Outlookから取得したスケジュールデータを管理するためのアイテムクラス

OutlookManager.cs

Outlookのスケジュールを取得するための管理クラス

using NetOffice.OutlookApi;
using NetOffice.OutlookApi.Enums;

namespace Test
{
    public class OutlookManager
    {
        public List<ScheduleItem> GetScheduleList(string mailOrName, DateTime date)
        {
            return GetScheduleList(mailOrName, date, date.AddDays(1));
        }

        public List<ScheduleItem> GetScheduleList(string mailOrName, DateTime start, DateTime end)
        {
            // 対象フォルダの取得
            var folder = GetCalenderFolder(mailOrName);

            // スケジュールの検索
            var items = GetScheduleItems(folder, start, end);

            // 定期的なスケジュールを展開して、ScheduleItemに変換
            var schedules = ExpansionAndConvert(items, start, end);

            return schedules;
        }

        private Application GetApplication()
        {
            return new Application();
        }

        private MAPIFolder GetCalenderFolder(string mailOrName)
        {
            var outlook = GetApplication();

            // var oFolder = outlook.Session.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
            // var rObject = outlook.Session.CreateRecipient("rm20160917120031@jp.nssol.nssmc.com");
            var rObject = outlook.Session.CreateRecipient(mailOrName);
            var oFolder = outlook.Session.GetSharedDefaultFolder(rObject, OlDefaultFolders.olFolderCalendar);
            // oFolder.Items.IncludeRecurrences = true;
            // Console.WriteLine(oFolder.Name);

            return oFolder;
        }

        private _Items GetScheduleItems(MAPIFolder folder, DateTime start, DateTime end)
        {
            // Filter apply
            string startDate = start.ToString("yy/MM/dd");
            string endDate = end.ToString("yy/MM/dd");
            string filter = $"[Start] >= '{startDate}' AND [Start] <= '{endDate}'";
            // Console.WriteLine(filter);
            var list = folder.Items.Restrict(filter);

            // Set Sort
            // list.Sort("[Start]", false);

            return list;
        }

        private List<ScheduleItem> ExpansionAndConvert(_Items items, DateTime start, DateTime end)
        {
            var ret = new List<ScheduleItem>();

            foreach (AppointmentItem item in items)
            {
                if (item.IsRecurring)
                {
                    var pattern = item.GetRecurrencePattern();
                    DateTime first = new DateTime(start.Year, start.Month, start.Day, item.Start.Hour, item.Start.Minute, 0);
                    DateTime last = new DateTime(end.Year, end.Month, end.Day);
                    for (DateTime cur = first; cur <= last; cur = cur.AddDays(1))
                    {
                        try
                        {
                            // ここの取得が成功したらスケジュールが存在するって判定になる
                            var recur = pattern.GetOccurrence(cur);
                            var curEnd = new DateTime(cur.Year, cur.Month, cur.Day, item.End.Hour, item.End.Minute, 0);
                            ret.Add(new ScheduleItem(item.Subject, cur, curEnd));
                        }
                        catch
                        { }
                    }
                }
                else
                {
                    ret.Add(new ScheduleItem(item.Subject, item.Start, item.End));
                }
            }

            // 指定の日付幅だけにする、ついでにソート
            ret = ret.Where(x => start <= x.Start)
                     .Where(x => x.End <= end)
                     .OrderBy(x => x.Start)
                     .ToList();

            return ret;
        }
    }
}

ScheduleItem.cs

Outlookから取得したスケジュールデータを管理するためのアイテムクラス

com経由でのアクセスを基本的にやるので、comデータを直接管理しないようにするために一旦自分の管理クラスに変換したほうが良いかと思います。(経験則)

namespace Test
{
    public class ScheduleItem
    {
        public string Title { get; set; }

        public DateTime Start { get; set; }

        public DateTime End { get; set; }

        public ScheduleItem(string title, DateTime start, DateTime end)
        {
            this.Title = title;
            this.Start = start;
            this.End = end;
        }

        public override string ToString()
        {
            return $"({Start}~{End}) {Title}";
        }
    }
}

使い方

Program.cs

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            OutlookManager outlookManager = new OutlookManager();

            // メールアドレス もしくは 名前 を指定
            // 対象日時を指定(Start~Endでの指定もできます)
            var schedules = outlookManager.GetScheduleList("test@test.com", DateTime.Today);
            foreach(var s in schedules)
                Console.WriteLine(s);
            // Console.WriteLine($"Schedules count={schedules.Count}");
        }
    }
}

実行結果

メールアドレス・当日の2パラメータで指定し、当日のスケジュールデータを3件取得できました。

(2018/12/10 14:00:00~2018/12/10 15:00:00) 会議1
(2018/12/10 15:00:00~2018/12/10 16:00:00) 会議2
(2018/12/10 16:00:00~2018/12/10 17:30:00) 会議3






よければ、SNSにシェアをお願いします!

2件のフィードバック

  1. 参考になる記事ありがとうございます。

    上記コードのまま実行してみると下記エラーが発生します。

    NetOffice.NetOfficeException: ‘Factory is not initialized with NetOffice assemblies.’

    ブログに下記記載ありますが、DLLの参照とはどのようにするものでしょうか?

    ネットから何かDLするのでしょうか?

    作成方法など調べましたが、今回何を記載すればよいのか分からず困っています。。。

    >開発時にOfficeのバージョン指定でDLLを参照しますが、これを使うとバージョンの依存部分を吸収してくれて、開発・運用で別々のオフィスでも可能な限り実行できるのかなと思います。(未検証)

  2. もしかしたら同じ件で引っかかる方があるかも、と返信します。

    自環境(VS2017)でこのコードを実行してみたところNetOffice.NetOfficeException: ‘Factory is not initialized with NetOffice assemblies.’が発生し、どのように解決できるかなと検索してみたところ、NetOffice Frameworkのツイートを見つけました。
    https://twitter.com/NetOfficeFw/status/1285855990307487744?s=20

    これによればNetOffice.Coreのv1.7.4.4またはv1.7.4.11を使ってる場合に発生している様子で、NetOfficeFwパッケージに移行して解決するとありました。
    (ツイートにもありますが、移行方法はこちらhttps://netoffice.io/migrate-notice/)

    自環境ではNetOfficeFwパッケージに移行することで同エラーを回避し、本ソースコードにてOutlookの予定表を入手できました。参考まで。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントする