Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
54
Help us understand the problem. What is going on with this article?
@propella

Microsoft Outlook API で遊ぶ

会社の予定表として Outloook にお世話になっているが、プログラムで操作する方法を調べた。普通こういうの curl 使うもんだと思うが、最近気に入っている Jupytor 使用。

Outlook の操作には Graph API を使う

アプリを作る

Outlook を操作するにはまずアプリを登録する。

  • Application Registration Portal に行く
  • Application Name を決める。
  • Generate New Password で client_secret を取得。Azure AD 1 を使う場合無くても使える。
  • Add Platform
    • https://developer.microsoft.com/en-us/graph/docs/concepts/auth_overview に説明があるが、良くわからなかった。自分で調べた結果は以下。
    • Web: Web アプリ向け
    • Redirect URLs に OAuth2 の authorization code を受ける URL を指定する。
    • token の受け取りに client_secret が必要。
    • Native Application
    • Custom Redirect URIs hogehoge://auth のようなカスタム URL を指定。携帯アプリではこの URL で authorization code を受ける。
    • token の受け取りに client_secret は不要な時がある。
  • Delegated Permissions
    • Calendars.Read を追加 (Azure AD のみ)
    • 一旦アプリにログインすると後から追加した Permission は無効のままなので、変更したい場合は https://portal.office.com/account/#apps で一旦 Revoke する。このアドレスは work or school 用。フリーアカウントで revoke する方法は見つからなかった。

実際に認証をやってみる

詳しい話は後にして、実際に認証してみる。アプリを作ったら結局以下の三つのパラメータが手に入るので、jupytor で試すときは次のように保存しておく。

APP = {
    'client_id': 'YOUR_CLIENT_ID', # 自動生成されたもの
    'redirect_uri': 'http://localhost:10101/authorized', # 自分で決める。例として http://localhost:10101/authorized を使う。
    'client_secret': 'YOUR_SECRET' # 自動生成されたもの
}

このパラメータを使い、次のような URL をブラウザに入れて Outlook アカウントにログインする。

https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=(client_id)&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A10101%2Fauthorized&response_mode=query&scope=https%3A%2F%2Fgraph.microsoft.com%2Fcalendars.read+offline_access&state=1234

ブラウザで承認すると、http://localhost:10101/authorized にリダイレクトする。この URL は適当なのでエラーになるが、そのときブラウザのアドレスバーにある URL の code パラメータから authorization code を抜き出す。例えば

http://localhost:10101/authorized?code=HOGEHOGE&state=1234&session_state=6dbc8b19-2b4e-4f74-bb28-a095f37b3a60

ならば authorization code は HOGEHOGE となる。authorization code から refresh_token を取得する。

def get_refresh_token(code, app):
    data = {
        'grant_type': 'authorization_code',
        'client_id' : app['client_id'],
        'code': code,
        'redirect_uri' : app['redirect_uri'],
        'scope': 'https://graph.microsoft.com/calendars.read offline_access',
        'client_secret': app['client_secret'],
    }
    print('data: %s' % data)
    global response
    response = requests.post(
        'https://login.microsoftonline.com/common/oauth2/v2.0/token',
        data=data,
    )
    if response.status_code == 200:
        token = response.json()['refresh_token']
        return response, token
    return response, None

refresh_token = get_refresh_token(APP, 'HOGEHOGE')

取得した refresh_token を使って、今度は access_token を取得する。

def get_access_token(app, token):
    params = {
        'grant_type': 'refresh_token',
        'client_id' : app['client_id'],
        'refresh_token': token,
        'redirect_uri' : app['redirect_uri'],
        'client_secret' : app['client_secret'],
        'scope': 'https://graph.microsoft.com/calendars.read offline_access',
    }

    response = requests.post(
        'https://login.microsoftonline.com/common/oauth2/v2.0/token',
        data=params,
    )
    return response.json()['access_token']

access_token = get_access_token(APP, refresh_token)
access_token

access_token が手に入ったら認証は完了。以下に何をやったか書く。

認証

認証には OAuth2 という仕組みが使われる。ザクっと次の流れになる。

  1. アプリはユーザに Office 認証サーバへのリンクを用意する。リンクにあらかじめ決めて置いた redirect_url を埋め込む。
  2. ユーザはブラウザで Office アカウントにログインする。
  3. Office 認証サーバは redirect_url にリダイレクトする。その際 URL に authorization code 付加される。
  4. 普通は URL にあるアプリサーバで認証処理を継続する。アプリサーバが無いときはブラウザがエラーになるので手で authorization code をコピペして使う。
  5. authorization code を token API に POST して access_token をもらう。出来たら refresh_token ももらう。
    • authorization code はもう使わないので忘れる。
  6. token API は refresh_token から access_token を発行する事も出来る。
  7. 認証終わり、access_token をヘッダに入れて API にアクセスする。

二つの認証エンドポイント: Azure AD と Azure AD 2.0

ややこしい事に、認証のためのエンドポイントが二つある。試行錯誤して次の事がわかった。上の例では Azure AD 2.0 を使った。

  • Azure AD
    • 会社や学校のアカウント専用。
    • Native Aplication を有効にすると client_secret 無しでも refresh_token を取得出来る。
    • 面白い事に Native Aplication を有効にするだけで Web の redirect_uri を使っても client_secret 無しの refresh_token 取得が出来る。
    • 認証時のパラメータには特に権限を入れない。Application Registration Portal の Delegated Permissions で設定してある。
  • Azure AD 2.0

Azure AD 2.0 の scope 指定方法

Requesting individual user consent

によると、スコープは Application ID URI と Scope value を連結した物。

カレンダーを取得

単純にイベントの内容を取得するには List events API を使う。

def graph(path, params={}):
    headers = {
        'Authorization': 'Bearer %s' % access_token,
        'Prefer': 'outlook.timezone="Asia/Tokyo", outlook.body-content-type="text"'
    }
    response = requests.get(
        path,
        params=params,
        headers=headers,
    )
    if response.status_code != 200:
        print(response.json())
    return response

response = graph('https://graph.microsoft.com/v1.0/me/events')
response.json()

これで最近追加した順に 10 件イベントが返る。ただ、これでは繰り返しの予定が一つのイベントとして返されるので役に立たない。

例えば、繰り返すかどうかに関わらず先の二週間分を取得するには 代わりに CalendarView を使う。

from datetime import datetime, timedelta

start = datetime.today()
end = start + timedelta(days=14)

response = graph("https://graph.microsoft.com/v1.0/me/calendar/calendarView",
                 {
                     'startDateTime': start.isoformat(),
                     'endDateTime': end.isoformat(),
                     '$orderby': 'start/dateTime',
                 })
response.json()

上で、クエリの中にある $orderebyOData というクエリ言語。OData を使うと共同のやり方でデータの検索や、フィルタ、並び替えなどを行える。

参考

日本語約へのリンクもある。

54
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
54
Help us understand the problem. What is going on with this article?