自动添加 12306 火车行程到 Google Calendar

月初短短几天乘了 8 趟火车,反复调出 App 页面看登车信息很麻烦,由此起了念头,可否在下单后就自动添加行程到 Google Calendar 呢?

我的想法是,收到 12306 购票或改签成功的邮件后自动读取邮件内容,若乘车人是我的名字就把时间、车站、班次等信息加到 Google Calendar 的 Event 里,并且设置一个提前两小时的提醒。

在 Gmail 中设置 filter

首先在 Gmail 中创建一个 filter,筛选出发件人是 12306 并且内容是购票或改签成功的邮件,自动将它们移到 RailwaySchedules 的 label 下。

创建 Google Apps Script

Google Apps Script 中创建新的 script,复制以下代码。


function autoAddRailwayEvent() {
  try {
    // Define the Gmail label that stores the filtered emails
    var label = GmailApp.getUserLabelByName("RailwaySchedules");
    if (!label) {
      Logger.log("Label not found: 'RailwaySchedules'");
      return;
    }

    // Get only unread threads (emails)
    var threads = label.getThreads();
    var calendar = CalendarApp.getDefaultCalendar();

    // Iterate through all unread threads (emails)
    for (var i = 0; i < threads.length; i++) {
      var message = threads[i].getMessages()[0];
      if (!message.isUnread()) {
        continue; // Skip already read messages
      }

      var body = message.getBody()
      Logger.log("Processing email body: " + body);  // Log email body for debugging

      // Check if the body contains the expected information
      if (body.includes("张三,")) {
        // Extract the paragraph after "name" and before "ticket"
        var infoSection = body.split('张三,')[1].split(',电子客票。')[0].trim();

        // Extract details by splitting the paragraph based on commas
        var details = infoSection.split(',');
        if (details.length < 2) {
          Logger.log("Unexpected format in infoSection: " + infoSection);
          continue;
        }
  
        var dateTime = details[0];  
        var station = details[1];  
        var description = details.slice(2).join(','); // Join the rest as description

        // Parse the date and time
        var year = dateTime.substring(0, 4);
        var month = dateTime.substring(5, 7) - 1;  // Months are zero-indexed
        var day = dateTime.substring(8, 10);
        var hour = dateTime.substring(11, 13);
        var minute = dateTime.substring(14, 16);

        var eventDate = new Date(year, month, day, hour, minute);

        // Add the event to Google Calendar with a 2-hour reminder
        calendar.createEvent(station, eventDate, new Date(eventDate.getTime() + 60 * 60 * 1000))
          .setDescription(description)
          .addPopupReminder(120);  // Reminder 2 hours before
        Logger.log("Event created for: " + station + " at " + eventDate);

        // Mark the email as read after processing
        threads[i].markRead();
      } else {
        Logger.log("Email does not contain expected ticket info: " + body);
      }
    }
  } catch (e) {
    Logger.log("Error: " + e.message);
  }
}

张三 替换成自己的名字,命名该 script 后保存。

这个脚本会执行以下动作:

  • 检查邮箱 RailwaySchedules 标签下是否有未读邮件
  • 遍历未读邮件,若含有指定姓名,则截取邮件中 张三,,电子客票。 部分内容为 infoSection
  • 来 split infoSection,将得到的 array[0] 转换为日期和时间,array[1] 为车站。
  • 将车站信息作为标题、其余内容为描述添加到 Google Calendar Event,设置时间日期并提前两小时提醒
  • 将对应邮件标为已读

image.png

12306 的邮件模板通常如上图,所以用 张三,,电子客票。 作为 split 的分隔字符能保证恰好截取到自己的购票信息。

创建定时 Trigger

偷懒用 ChatGPT 原话。我设置的是每小时运行一次。

Go to Google Apps Script or from your Gmail/Google Calendar, click the gear icon in the top-right corner and select See all settings > Advanced > Google Apps Script.

In the Apps Script editor, click on the clock icon on the left-side panel (called Triggers).

Click the + Add Trigger button at the bottom right.

Set up the trigger as follows:  

  • Choose which function to run: Select the function that processes the Gmail label (in this case, checkLabelAndProcessEmails)
  • Choose which deployment should run: Select “Head” (the default).
  • Select event source: Choose “Time-driven.”
  • Select type of time-based trigger: Choose an interval, such as “Minute timer,” “Hour timer,” or “Day timer.”
  • Select time interval: Choose how frequently you want the script to run (e.g., every 10 minutes, once an hour, or once a day)

运行试试看,Google Calendar 里已经有相应 event 了呢!

image.png

总结

感觉代码可能有疏漏,但之后发现再说吧。这个法子也适用于其他购票提醒,对 script 做针对性修改就可以,暂时我没有更多需要大量处理的行程,姑且就先这样。

Comments