皆さんGoogle Apps Script好きですかー?自分はV8になってから好きになりました
はじめに
📦📦📦📦📦
📦 am͜a͉zon 📦
📦📦📦📦📦
今回はAmazon発送メール × Gmail × Google Calendarの組み合わせなので、Outlookの方は180°回ってお帰りいただくか今すぐGmailに移行しましょう。
なぜ今更GAS???
察しの良い方はTwitterでお気づきかもしれませんが、コロナ感染者が異常に多い所に5月頃引っ越して一人暮らしを始めました。(ついでにGASからIHになりました。ぴえん🥺)
単純な話、今までは実家暮らしで誰かが受け取ってくれていたので、配達日を把握して自分が家に居る必要がなかったんですね。
宅配ボックス使えよと言われる前に言いますが宅配ボックスまで行くのが面倒
このスクリプトの特徴
もちろん自宅等での受け取りにも対応していますよ。Amazon発送メールをGASでゴリゴリするやつ、正規表現乱用して営業所止めにも対応した
— 冷凍こめ (@come25136_spd) July 9, 2020
そのうちQiitaに書く pic.twitter.com/a1roODWU91
処理フロー
GmailにAmazonから発送メールが届く
↓←────────────┐
イベントトリガー等で定期処理┘
↓
Googleカレンダーに登録
コピペで動くコード ...の前に
日付&時刻の便利ライブラリ「Moment.js」をGoogle Apps Scriptで使う方法 を参考にGASでMoment.jsを使えるようにしてください。
コピペで動くコード
2, 3行目は各自調整してください。
function amazonEvent() {
const daysAgo = 1 // n日前から実行日時までのメールを処理する
const calendar = CalendarApp.getCalendarById('カレンダーID') // http://www.sukicomi.net/2018/07/google-calendarid.html
const now = Moment.moment()
GmailApp
.search(`from:(Amazon.co.jp) Amazon.co.jpでのご注文 after:${now.clone().subtract(daysAgo, 'd').format('YYYY/MM/DD')}`)
.sort((a, b) => a.getLastMessageDate() - b.getLastMessageDate())
.forEach(thread => {
const messages = thread.getMessages()
messages
.sort((a, b) => a.getDate() - b.getDate()) // 古い日付が先に来るようにする
.forEach(message => {
const msgRecvDate = Moment.moment(message.getDate())
const msgBody = message.getPlainBody()
// Kindleを除く
const deliveryScheduleMsgResult = msgBody.match(/お届け予定日?時?[::](.+)配送(状況は下記ページ|オプション)/s)
if (deliveryScheduleMsgResult === null) return
const [, deliveryScheduleMsgRaw] = deliveryScheduleMsgResult // 冗長だけどデバッグ用に変数化
const deliveryScheduleMsg = deliveryScheduleMsgRaw.replace(/^\s+|\s+$|.{3,},\s|\r?\n/g, '').replace(/[\t\s]+/, ' ')
const [deliveryStartScheduleMsg, deliveryEndScheduleMsg] = deliveryScheduleMsg.split(' - ')
const [deliveryStartDateMsg, deliveryStartTimeMsg] = deliveryStartScheduleMsg.split(' ')
const deliveryStartTimeMsgIsTime = /\d\d:\d\d/.test(deliveryStartTimeMsg)
const [, deliveryEndDateMsg, deliveryEndTimeMsg] = (deliveryEndScheduleMsg || deliveryStartScheduleMsg).match(/([0-1]\d\/[0-3]?\d)?\s?(([01][0-9]|2[0-3]):[0-5][0-9])?/)
// 年跨ぐ場合のメールを見たことないのでバグるかも
const deliveryStartDate = Moment.moment(`${deliveryStartDateMsg} ${deliveryStartTimeMsgIsTime ? deliveryStartTimeMsg : '00:00'}`, 'MM/DD HH:mm').set('y', msgRecvDate.year())
const deliveryEndDate = Moment.moment(`${deliveryEndDateMsg || deliveryStartDateMsg} ${deliveryEndTimeMsg || '23:59'}`, 'MM/DD HH:mm').set('y', msgRecvDate.year())
const [, orderNumber] = msgBody.match(/注文番号:?\s?(.+)/)
const oldEvents = calendar.getEvents(deliveryStartDate.clone().subtract(2, 'w').toDate(), deliveryStartDate.clone().add(2, 'w').toDate())
const oldEvent = oldEvents.find(e => e.getTag('order_number') === orderNumber)
// 正規表現1つにまとめたいけど上手く動いてるので妥協
const [, deliveryAddMsg] = msgBody.match(/お届け先:\s*(.+)\r?\n\s{0,5}\r?\n.*===/s)
const [name, addressMsg] = deliveryAddMsg.replace(/お客様の商品は.+|===.+/s, '').split(' 様')
if (addressMsg === undefined) {
console.log(message)
}
const address =
addressMsg
.replace(/\r?\n/g, '') // 改行削除
.replace(/\s{2,}/g, ' ') // スペースが2個以上連続しているのを削除
.replace(/[1-9]+件中[1-9]+件目の発送.+/, '')
.replace(/\s不在時.*/, '') // 住所の最後に「不在時はOKIPPA希望」と入れてるのでそれを削除(削除しないとGoogle Mapで上手く表示されない)
const title = /営業所/.test(name) ? `荷物営業所止め(${name})` : `荷物受け取り`
const description = `<a href="${message.getThread().getPermalink()}">メールを開く✉</a><br>${orderNumber}`
if (oldEvent) {
oldEvent
.setTitle(title)
.setDescription(description)
.setLocation(address)
const setTime = deliveryStartTimeMsgIsTime ? oldEvent.setTime : oldEvent.setAllDayDates
if (deliveryStartTimeMsgIsTime)
setTime(deliveryStartDate.toDate(), deliveryEndDate.toDate())
else
oldEvent.setAllDayDate(deliveryStartDate.toDate())
} else {
const createEvent = deliveryStartTimeMsgIsTime ? calendar.createEvent : calendar.createAllDayEvent
const event = createEvent(
title,
deliveryStartDate.toDate(),
deliveryEndScheduleMsg ? deliveryEndDate.toDate() : undefined,
{
description,
location: address
}
)
event.setTag('order_number', orderNumber)
}
})
})
}
使い方
自由に煮るなり焼くなりしてもらって構いませんが、自分はイベントトリガーのタイマーをこんな感じに設定して使っています。
注意
Amazonは複数商品の注文を複数日に分けて配達してくれる機能があるのですが、いつもまとめて配達してもらっているので動作確認出来ていません。
これに関しては発送後の追跡番号で識別すれば良いだけなのですが、自分が困ったら対応するということで。そのうち。
参考にさせていただいた記事
Amazonの注文確認のgmailから、googleカレンダーにその受け取り時刻の予定を自動で入れる - Qiita
さいごに
Amazonのお急ぎ便大体翌日に来るけど、深夜に注文すると寝るまでが今日理論で配達が翌々日になるので脳がバグる
アルゴリズムに何の捻りもないのと、GASは公式ドキュメントが充実している為、あえてコードの解説を書いていませんが何かあれば@come25136_spdまで気軽にどうぞ