Gmailの新着メールをLINEに転送する by Google Apps Script
Gmailで受信したメールをGASでLINEに転送する
私事ながら2019年に結婚しました。それから結婚式の式場を選び、日取りを決めて、当日の準備に当たります。すると、式場から打ち合わせのメールが不定期に飛んできます。
私はメールの受信箱を頻繁に見ないので、やりとりはSlackにしたいと式場に申し出てもあえなく断られました。そこで、GmailからLINEにメールを転送すれば見逃しがなくなると考え、Google Apps Script(以下、GAS)で実装しました。
本記事では、GmailからLINEに特定のメールを転送する方法をご紹介します。
関連記事:
GASでGmailの受信メールをLINEに転送するコードを解説します
まずコードを掲載します。その後、コメントを付与した箇所に解説を加えていきます。
const ENDPOINT = 'https://notify-api.line.me/api/notify'
// 1. 転送したいメールの送信元アドレスを指定する
const FROM_ADDRESS = [''].join(' OR ')
// 2. トリガーの設定間隔と合わせる
const MINUTES_INTERVAL = 5
function fetchNotices() {
const now = Math.floor(new Date().getTime() / 1000)
const intervalMinutesAgo = now - (60 * MINUTES_INTERVAL)
// 3. 検索条件を設定
const query = `is:unread from:(${FROM_ADDRESS}) after:${intervalMinutesAgo}`
// 4. メールを取得する
const threads = GmailApp.search(query)
const mails = GmailApp.getMessagesForThreads(threads)
const notices = []
for (const messages of mails) {
const latestMessage = messages.pop()
const notice = `
--------------------------------------
件名: ${latestMessage.getSubject()}
受信日: ${latestMessage.getDate().toLocaleString()}
From: ${latestMessage.getFrom()}
--------------------------------------
${latestMessage.getPlainBody().slice(0, 350)}
`
notices.push(notice)
// 5. メールを既読にする
latestMessage.markRead()
}
return notices
}
1. 転送したいメールの送信元アドレスを指定する
const FROM_ADDRESS = [''].join(' OR ')
**配列内に転送したいメールの送信者のアドレスを追加します。**これは@example.com
のようにドメインを指定しても構いません。これで、全ての新着メールではなく、特定の送信者からのメールだけ転送するような設定ができます。
もしこの配列が空である場合、定数FROM_ADDRESS
には空文字列が代入されるため、全てのメールを取得することになります。
このため、全てのメールをGmailからLINEに転送したい場合、特にメールアドレスを記述する必要はありません。
2. 5分前までの新着メールを取得する
const MINUTES_INTERVAL = 5
定数MINUTES_INTERVAL
で5分前までの新着メールを転送対象とします。この時間は、あとで設定するトリガー(関数の実行タイミング)と合わせるようにします。
3. 検索条件を設定(フィルター設定)
const query =
`is:unread from:(${FROM_ADDRESS}) after:${intervalMinutesAgo}`
query
はメールの検索条件です。この条件に該当するメールだけを転送対象とします。以下が今回使う絞り込みの条件です。
| key | value | 条件 | 例 | |--|--|--|--| | is | unread | 未読のメールのみ | is:unread | | from | [email protected] OR yyy.com | 転送するメールの送信元 | from([email protected] OR yyy.com) | | after | 1592707480 | この時間以降のメール | after:1592707480 |
この検索条件は、Gmailのフィルター設定をすると自動で作成されます。条件を変更する場合は、Gmailのフィルター設定から条件を指定して、その結果を使ってコードを書き換えましょう。
なお、検索条件の組み立てはビルダーパターンで設計するのが定石です。
ただし、メールの検索条件を頻繁に変更することはないので、今回は文字列で必要十分です。
4. 新着メールを取得する
const threads = GmailApp.search(query)
const mails = GmailApp.getMessagesForThreads(threads)
const notices = []
for (const messages of mails) {
const latestMessage = messages.pop()
// ...
}
検索条件に該当するメールは、GmailAppのsearchメソッドで取得します。返り値の型はGmailThread[]
です。
次にgetMessagesForThreads(threads)
メソッドで、それぞれのメールの一連のやりとりを取得します。返り値はGmailMessage[][]
です。
for (const messages of mails)
で2次元配列mailsの値をmessagesに格納します。for (const a of b)
は、配列bの値を変数aに格納する記法です。
これと似た記法でfor (const a in b)
というものもありますが、こちらは配列のindexを取得する記法です。
const array = ['a', 'b', 'c']
for (const char of array) {
console.log(char)
}
// a
// b
// c
for (const index in array) {
console.log(index)
}
// 0
// 1
// 2
これで最新のメールを取得できました。
GmailにおけるThreadとMessageの違い
ここでThread
とMessage
という用語の整理をしましょう。細かい内容なので読み飛ばしてもらっても構いません。
search
メソッドで取得できるThread
は「あるメールとそのメールに対する一連の返信」です。あるメールを送った後そのメールに返信がつき、さらにそのメールに返信する、というのがメールの使い方です。Threadには一番最初のメールとそれに付随する返信を含んだものです。
一方、getMessagesForThreads
メソッドで取得するMessage
は単体のメールです。元のメールならそのメール、返信ならその返信です。
つまり、Thread
は最初のメールとそれに対する返信メールです。一件一件のメールそのものはMessage
と呼ばれているのです。これがThreadとMessgeの違いです。
5. 新着メールを既読にする
latestMessage.markRead()
markRead()
メソッドでメールを既読にできます。これで毎回Gmailの未読件数の増加を防げますね。
5分単位で新着メールをチェックする
新着メールを取得する処理を記述できました。次は、5分ごとにLINEに転送する設定を書きます。
GASのトリガーを5分単位で設定する
次に、トリガーを設定しましょう。上記で設定した間隔(今回は5分)間隔でGASを動かすようにします。
GASのトリガー設定方法は「GASのトリガーを設定する」をご覧ください。
実行する関数はmain関数にします(記事最後のコード全文を参照)。
LINEにメールを転送する
最後にLINEにメールを転送する関数を作成しましょう。
const LINE_NOTIFY_TOKEN = PropertiesService
.getScriptProperties()
.getProperty('LINE_NOTIFY_TOKEN')
const ENDPOINT = 'https://notify-api.line.me/api/notify'
function send(mail) {
const options = {
'method': 'POST',
'headers': {'Authorization': `Bearer ${LINE_NOTIFY_TOKEN}`},
'payload': {'message': mail},
}
UrlFetchApp.fetch(ENDPOINT, options)
}
LINEに転送するためには、LINE Notifyのトークンを取得する必要があります。
また、取得したトークンはPropertiesServiceで使えるように、GASのプロパティに格納しておきましょう。
これでメールの転送準備ができました。
実際にメールを転送してみる
実際に自分にメールを送ってみて、LINEに転送できているか確認してみましょう。
きちんと転送されていますね。なお、コード全文は記事の最後に記載しています。
まとめ
式場を決めてすぐの頃、妻との間で「式場からのメール確認した?」というやりとりを何度かしたので、これは二人がよく見るLINEに転送せねばと思いコードを実装しました。
GASのおかげで妻との会話の始まりが「メールチェックした?してない?」ではなく、「返信内容をどうする?」という本質的な内容に変化し、効果を実感できました。
非同期コミュニケーションが生まれる仕組みを作り、時間を有効に活用しましょう 🎉
コード全文を記載します
今回使ったコードの全文を記載します。
const LINE_NOTIFY_TOKEN = PropertiesService
.getScriptProperties()
.getProperty('LINE_NOTIFY_TOKEN')
const ENDPOINT = 'https://notify-api.line.me/api/notify'
const FROM_ADDRESS = [''].join(' OR ')
const MINUTES_INTERVAL = 5
function main() {
const notices = fetchNotices()
if (notices.length === 0) {
return
}
for (const notice of notices) {
send(notice)
}
}
function fetchNotices() {
const now = Math.floor(new Date().getTime() / 1000)
const intervalMinutesAgo = now - (60 * MINUTES_INTERVAL)
const query = `(is:unread from:(${FROM_ADDRESS}) after:${intervalMinutesAgo})`
const threads = GmailApp.search(query)
if (threads.length === 0) {
return []
}
const mails = GmailApp.getMessagesForThreads(threads)
const notices = []
for (const messages of mails) {
const latestMessage = messages.pop()
const notice = `
--------------------------------------
件名: ${latestMessage.getSubject()}
受信日: ${latestMessage.getDate().toLocaleString()}
From: ${latestMessage.getFrom()}
--------------------------------------
${latestMessage.getPlainBody().slice(0, 350)}
`
notices.push(notice)
latestMessage.markRead()
}
return notices
}
function send(notice) {
if (LINE_NOTIFY_TOKEN === null) {
Logger.log('LINE_NOTIFY_TOKEN is not set.')
return
}
const options = {
'method': 'POST',
'headers': {'Authorization': `Bearer ${LINE_NOTIFY_TOKEN}`},
'payload': {'message': notice},
}
UrlFetchApp.fetch(ENDPOINT, options)
}
Happy Coding 🎉