当我将 "METHOD: REQUEST" 添加到 iCalendar 时,Gmail 停止将其识别为事件

When I add "METHOD: REQUEST" to iCalendar, Gmail stops recognizing as event

我正在使用 iCalendar 为 Gmail 用户安排活动。但是,我希望能够发送更新,if/when 事件发生变化。我读到必须使用 METHOD:REQUEST 才能允许更新。

但是,当我将 METHOD:REQUEST 添加到我的 ics 文件时,Gmail 停止将其识别为日历邀请。

这是工作示例 WITHOUT "METHOD:REQUEST"

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Cratic//Cratic Huddle//EN
NAME:Cratic Huddle
X-WR-CALNAME:Cratic Huddle
TIMEZONE-ID:Europe/Berlin
X-WR-TIMEZONE:Europe/Berlin
BEGIN:VEVENT
UID:60212c8395841f2cd057864f@cratic.ai
SEQUENCE:0
DTSTAMP:20210208T130601Z
DTSTART:20210219T133059Z
DTEND:20210219T140059Z
SUMMARY:Cratic Huddle
DESCRIPTION:This is the information
ORGANIZER;CN="Izzi":mailto:firstname.lastname@gmail.com
ATTENDEE;ROLE=REQ-PARTICIPANT:MAILTO:firstname.lastname@gmail.com
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER:-PT15M
DESCRIPTION:Cratic Huddle
END:VALARM
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:-PT15M
ATTACH;VALUE=URI:Basso
END:VALARM
URL;VALUE=URI:cratic.ai
END:VEVENT
END:VCALENDAR

以上完美运行; Gmail 弹出一个按钮,询问我是否要接受。

这是不工作的例子 WITH "METHOD:REQUEST"

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Cratic//Cratic Huddle//EN
METHOD:REQUEST
NAME:Cratic Huddle
X-WR-CALNAME:Cratic Huddle
TIMEZONE-ID:Europe/Berlin
X-WR-TIMEZONE:Europe/Berlin
BEGIN:VEVENT
UID:60212c8395841f2cd057864f@cratic.ai
SEQUENCE:0
DTSTAMP:20210208T125937Z
DTSTART:20210219T133059Z
DTEND:20210219T140059Z
SUMMARY:Cratic Huddle
DESCRIPTION:This is the information
ORGANIZER;CN="Izzi":mailto:firstname.lastname@gmail.com
ATTENDEE;ROLE=REQ-PARTICIPANT:MAILTO:firstname.lastname@gmail.com
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER:-PT15M
DESCRIPTION:Cratic Huddle
END:VALARM
BEGIN:VALARM
ACTION:AUDIO
TRIGGER:-PT15M
ATTACH;VALUE=URI:Basso
END:VALARM
URL;VALUE=URI:cratic.ai
END:VEVENT
END:VCALENDAR

这会在 google 中生成一封空白电子邮件,并附有 .ics 文件。它不会出现在日历或其他任何地方。

这两个 iCalendar 文件在其他方面完全相同。但出于某种原因,添加 METHOD:REQUEST 会破坏 ics 文件/google 的读取能力。

为什么??

好的 - 经过数小时阅读 RFC5546、Whosebug 和许多其他博客,我终于有了答案。

范围:

  1. 发送日历邀请到 Gmail / Outlook / Privateemail(namecheap 的电子邮件客户端)
  2. 电子邮件客户端自动识别 .ics 文件并生成“接受”模板
  3. 在客户日历中自动显示为“暂定”的事件
  4. 发送自动移动客户端日历事件的事件修订

有两个基本原则对完成这项工作至关重要:

  1. .ics 文件的 内容 必须与 Gmail / Outlook 社区的 .ics 文件非常匹配,这包括参数 和参数的顺序

  2. .ics 文件附加到电子邮件传输的方式很奇怪但很关键:(a) .ics 文件必须变成 'base64',以及 (b) headers的文件需要给一个类型:'text/calendar;method=REQUEST;name="file.ics"'

下面我将给出每个示例,希望能节省其他人在此过程中的时间。

.ics 内容示例:

let iCal = 

`BEGIN:VCALENDAR
PRODID:-//Cratic//_Scheduler//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VEVENT
DTSTART:${DTStart}
DTEND:${DTEnd}
DTSTAMP:${DTStamp}
ORGANIZER;CN=name:mailto:name@gmail.com
UID:${event._id}@url.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=name@outlook.com;X-NUM-GUESTS=0:mailto:name@outlook.com
CREATED:${DTStamp}
DESCRIPTION:${event.body}
LAST-MODIFIED:${DTStamp}
LOCATION:${location}
SEQUENCE:${sequence}
STATUS:CONFIRMED
SUMMARY:${event.title}
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR`

请注意:以上顺序非常重要!并且文本周围不能有死的 space,即使前后多出一个 space 也会扰乱电子邮件客户端。此外,这是一个可重复使用的动态 iCal 事件模板,只要我保留 event._id 的记录,我就可以使用该 _id 向我的所有客户发送修订。

正在将 .ics 附加到电子邮件客户端:

// convert the invite to be base64 for attachment
const buf = Buffer.from(iCal.toString(), 'utf-8');
const base64Cal = buf.toString('base64');

// build the email
const sendEmail = async () => {
    const res = await client.transmissions.send({
        recipients: [{ address: 'name@outlook.com' }],
        content: {
          from: 'name@sparkmail.com',
          subject: req.body.a.title,
          text: req.body.a.body,
          attachments: [
            {
              name: 'invite.ics',
              type: 'text/calendar;method=REQUEST;name=\"invite.ics\"',
              data: base64Cal,
            },
          ],
        },
        options: { sandbox: false },
    });
}

// send the email
sendEmail();

请注意:附件类型对于 Outlook 识别事件至关重要。

虽然我确信还有其他/更好的方法可以与这些服务集成,但我发现上述步骤可以让我完成我的范围。