【问题标题】:Outlook Accept / Decline buttons don't show up for IcalendarIcalendar 不显示 Outlook 接受/拒绝按钮
【发布时间】:2015-04-28 11:54:40
【问题描述】:

我想从我的 Laravel 应用程序发送日历邀请。我希望这些邀请在 Outlook 中显示接受/拒绝/建议新时间/也许按钮,但由于某种原因我无法让它们显示

我需要这个,因为我想实现这个:

我的代码:

$icalendar = IcalendarUtil::genEvent(
    array('Me', 'me@example.com'),
    new DateTime(),
    null,
    array(
        'example@example.com' => 'John Doe'
    ),
    'Test subject',
    'Test location',
    'Test Description',
    true,
    true
);

Mail::send('nada', array(), function($message) use($icalendar)
{
    $message->from('example@example.com', 'John Doe');
    $message->to('me@example.com')->subject('Test Calendar Event');

    $attachment = Swift_Attachment::newInstance($icalendar, 'event.ics', 'text/calendar');

    $attachment->getHeaders()->addTextHeader('Content-Type', 'text/calendar');
    $attachment->getHeaders()->addTextHeader('Content-Transfer-Encoding', '7bit');
    $attachment->getHeaders()->addTextHeader('X-Mailer', 'Microsoft Office Outlook 12.0');
    $attachment->getHeaders()->addTextHeader('method', 'REQUEST');
    $attachment->getHeaders()->addTextHeader('charset', 'iso-8859-1');

    $message->attachAttachment($attachment);
});

$message->attachAttachment($attachment); 是我添加到 Illuminate\Mail\Message.php 的函数,用于添加使用 newInstance 创建的 Swift_Attachment。代码:

public function attachAttachment($attachment)
{
    $this->prepAttachment($attachment);
}

IcalendarUtil 类是由Arun Poudel 提供给我的:

<?php

/**
 * iCalendar util
 */
class IcalendarUtil
{

/**
 * Generates a iCalendar event.
 *
 * @param array $organizer
 * @param DateTime $from_date
 * @param DateTime $to_date
 * @param array $attendees
 * @param string $subject
 * @param string $location
 * @param string $description
 * @param bool $all_day_event
 * @param bool $rsvp
 * @return string
 * @static
 * @throws cbmException
 */
static public function genEvent(array $organizer, DateTime $from_date, DateTime $to_date = null, array $attendees = null, $subject = null, $location = null, $description = null, $all_day_event = false, $rsvp = true)
{
    if (!$all_day_event && $to_date === null)
    {
        throw new Exception('to_date is required when the event is not an all day event');
    }
    $organizer_name = $organizer[0];
    $ical = "BEGIN:VCALENDAR\r\n";
    $ical .= "VERSION:2.0\r\n";
    $ical .= "PRODID:-//Microsoft Corporation//Outlook 14.0 MIMEDIR//EN\r\n";
    $ical .= "METHOD:REQUEST\r\n";
    $ical .= "X-MS-OLK-FORCEINSPECTOROPEN:TRUE\r\n";
    $ical .= "BEGIN:VTIMEZONE\r\n";
    $ical .= sprintf("TZID:%s\r\n", date('T'));
    $ical .= "BEGIN:STANDARD\r\n";
    $ical .= "DTSTART:16010101T000000\r\n";
    $ical .= "TZOFFSETFROM:+0545\r\n";
    $ical .= "TZOFFSETTO:+0545\r\n";
    $ical .= "END:STANDARD\r\n";
    $ical .= "END:VTIMEZONE\r\n";
    $ical .= "BEGIN:VEVENT\r\n";
    $ical .= sprintf("UID:%s\r\n", rand());

    $ical .= sprintf("ORGANIZER;CN=\"%s\":MAILTO:%s\r\n", $organizer_name, $organizer[1]);
    foreach ($attendees as $email => $name)
    {
        $ical .= sprintf("ATTENDEE;");
        if ($name !== null)
        {
            $ical .= sprintf("CN=\"%s\";", $name);
        }
        if($rsvp)
        {
            $ical .= sprintf("RSVP=TRUE:");
        }
        $ical .= sprintf("mailto:%s;\r\n", $email);
    }
    $ical .= sprintf("LOCATION:%s\r\n", $location);
    $ical .= sprintf("DTSTAMP:%s\r\n", self::getDateTimeInUTCFormat());
    $ical .= "CLASS:PUBLIC\r\n";
    $ical .= sprintf("DTSTART:%s\r\n", self::getDateTimeInUTCFormat($from_date));
    if (!$all_day_event)
    {
        $ical .= sprintf("DTEND:%s\r\n", self::getDateTimeInUTCFormat($to_date));
    }
    $ical .= sprintf("SUMMARY:%s\r\n", $subject);
    $ical .= "TRANSP:OPAQUE\r\n";
    $ical .= "X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE\r\n";
    $ical .= "X-MICROSOFT-CDO-IMPORTANCE:1\r\n";
    $ical .= "X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY\r\n";
    $ical .= "X-MICROSOFT-DISALLOW-COUNTER:FALSE\r\n";
    $ical .= "X-MS-OLK-APPTLASTSEQUENCE:1\r\n";
    $ical .= "X-MS-OLK-AUTOSTARTCHECK:FALSE\r\n";
    $ical .= "X-MS-OLK-CONFTYPE:0\r\n";
    $ical .= sprintf("X-MS-OLK-SENDER;CN=\"%s\":MAILTO:%s\r\n", $organizer_name, $organizer[1]);
    $ical .= sprintf("X-ALT-DESC;FMTTYPE=text/html:%s\r\n", "<p>" . preg_replace('/\R/', "</p><p>", $description) . "</p>");
    $ical .= sprintf("X-MS-OLK-CONFTYPE:0\r\n");
    $ical .= "BEGIN:VALARM\r\n";
    $ical .= "TRIGGER:-PT15M\r\n";
    $ical .= "ACTION:DISPLAY\r\n";
    $ical .= "DESCRIPTION:Reminder\r\n";
    $ical .= "END:VALARM\r\n";
    $ical .= "END:VEVENT\r\n";
    $ical .= "END:VCALENDAR";
    return $ical;
}

static protected function getDateTimeInUTCFormat(DateTime $date = null)
{
    if ($date === null)
    {
        $date = new DateTime();
    }
    $date->setTimezone(new DateTimeZone('UTC'));
    return $date->format('Ymd\THis\Z');
}

}

电子邮件仅显示为带有 .ics 附件的电子邮件。我究竟做错了什么?为什么没有显示回复按钮?

【问题讨论】:

  • 在这里查看纯php实现:exchangecore.com/blog/sending-outlookemail-calendar-events-php,您可以按照这种方法在消息末尾附加日历。
  • 我在这里专门谈论 Laravel。我已经在我的帖子中链接到一个工作示例,但我需要它与 Laravel 的 Mail 类一起使用。
  • 是的,这就是为什么我没有把它作为答案,您可以按照这种方法准备附件,然后您可以将其附加到 laravel 电子邮件中。但是,在您的情况下,arun 的答案似乎更方便。
  • 我提供的第二个答案运气好吗?

标签: php email laravel swiftmailer


【解决方案1】:

您不希望将整个电子邮件的类型设置为文本/日历。您可能还需要添加电子邮件正文。所以,我的建议是附上日历,然后设置我的类型:

$message->attach('something.ics', array('mime' => 'text/calendar'))

编辑:

使用这个类来生成你的 iCal

<?php

/**
 * iCalendar util
 */
class IcalendarUtil
{

    /**
     * Generates a iCalendar event.
     *
     * @param array $organizer
     * @param DateTime $from_date
     * @param DateTime $to_date
     * @param array $attendees
     * @param string $subject
     * @param string $location
     * @param string $description
     * @param bool $all_day_event
     * @param bool $rsvp
     * @return string
     * @static
     * @throws cbmException
     */
    static public function genEvent(array $organizer, DateTime $from_date, DateTime $to_date = null, array $attendees = null, $subject = null, $location = null, $description = null, $all_day_event = false, $rsvp = true)
    {
        if (!$all_day_event && $to_date === null)
        {
            throw new Exception('to_date is required when the event is not an all day event');
        }
        $organizer_name = $organizer[0];
        $ical = "BEGIN:VCALENDAR\r\n";
        $ical .= "VERSION:2.0\r\n";
        $ical .= "PRODID:-//Microsoft Corporation//Outlook 14.0 MIMEDIR//EN\r\n";
        $ical .= "METHOD:REQUEST\r\n";
        $ical .= "X-MS-OLK-FORCEINSPECTOROPEN:TRUE\r\n";
        $ical .= "BEGIN:VTIMEZONE\r\n";
        $ical .= sprintf("TZID:%s\r\n", date('T'));
        $ical .= "BEGIN:STANDARD\r\n";
        $ical .= "DTSTART:16010101T000000\r\n";
        $ical .= "TZOFFSETFROM:+0545\r\n";
        $ical .= "TZOFFSETTO:+0545\r\n";
        $ical .= "END:STANDARD\r\n";
        $ical .= "END:VTIMEZONE\r\n";
        $ical .= "BEGIN:VEVENT\r\n";
        $ical .= sprintf("UID:%s\r\n" . rand());

        $ical .= sprintf("ORGANIZER;CN=\"%s\":MAILTO:%s\r\n", $organizer_name, $organizer[1]);
        foreach ($attendees as $email => $name)
        {
            $ical .= sprintf("ATTENDEE;");
            if ($name !== null)
            {
                $ical .= sprintf("CN=\"%s\";", $name);
            }
            if($rsvp)
            {
                $ical .= sprintf("RSVP=TRUE:");
            }
            $ical .= sprintf("mailto:%s;\r\n", $email);
        }
        $ical .= sprintf("LOCATION:%s\r\n", $location);
        $ical .= sprintf("DTSTAMP:%s\r\n", self::getDateTimeInUTCFormat());
        $ical .= "CLASS:PUBLIC\r\n";
        $ical .= sprintf("DTSTART:%s\r\n", self::getDateTimeInUTCFormat($from_date));
        if (!$all_day_event)
        {
            $ical .= sprintf("DTEND:%s\r\n", self::getDateTimeInUTCFormat($to_date));
        }
        $ical .= sprintf("SUMMARY:%s\r\n", $subject);
        $ical .= "TRANSP:OPAQUE\r\n";
        $ical .= "X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE\r\n";
        $ical .= "X-MICROSOFT-CDO-IMPORTANCE:1\r\n";
        $ical .= "X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY\r\n";
        $ical .= "X-MICROSOFT-DISALLOW-COUNTER:FALSE\r\n";
        $ical .= "X-MS-OLK-APPTLASTSEQUENCE:1\r\n";
        $ical .= "X-MS-OLK-AUTOSTARTCHECK:FALSE\r\n";
        $ical .= "X-MS-OLK-CONFTYPE:0\r\n";
        $ical .= sprintf("X-MS-OLK-SENDER;CN=\"%s\":MAILTO:%s\r\n", $organizer_name, $organizer[1]);
        $ical .= sprintf("X-ALT-DESC;FMTTYPE=text/html:%s\r\n", "<p>" . preg_replace('/\R/', "</p><p>", $description) . "</p>");
        $ical .= sprintf("X-MS-OLK-CONFTYPE:0\r\n");
        $ical .= "BEGIN:VALARM\r\n";
        $ical .= "TRIGGER:-PT15M\r\n";
        $ical .= "ACTION:DISPLAY\r\n";
        $ical .= "DESCRIPTION:Reminder\r\n";
        $ical .= "END:VALARM\r\n";
        $ical .= "END:VEVENT\r\n";
        $ical .= "END:VCALENDAR";
        return $ical;
    }

    static protected function getDateTimeInUTCFormat(DateTime $date = null)
    {
        if ($date === null)
        {
            $date = new DateTime();
        }
        $date->setTimezone(new DateTimeZone('UTC'));
        return $date->format('Ymd\THis\Z');
    }

}

此外,您可能需要在电子邮件中设置一些自定义标题。

encoding = '7bit'
header = 'Microsoft Office Outlook 12.0' // Not sure if this is needed, but we might need to fool microsoft

【讨论】:

  • 但是我没有得到接受、暂定和拒绝按钮。
  • @Basaa 是的。您可以在通过附件发送时附加其他详细信息,例如您发送的 ics 文件等,而在您的原始问题中没有这样做?
  • 感谢您的课程。该文件生成文件,但仍然没有接受/拒绝按钮。如果我将电子邮件发送到 Gmail 帐户,它确实会在电子邮件中显示该事件。为什么 Outlook 不显示它?
  • @Basaa 你设置了编码和标题吗?发到gmail账号可以吗?
  • 是的...虽然... Jeez Laravel 邮件很复杂。我必须在附件上设置标题吗?如何在 Laravel 中设置附件标题?尝试使用 Swift_Attachment::newInstance(...) 生成附件会给我各种奇怪的 fopen 错误。您能否为我提供一个使用 IcalendarUtil 类发送电子邮件的小型 Laravel sn-p?我花了这么多时间在这上面,这让我发疯了。
【解决方案2】:

注意:我之前发布的 IcalendarUtil 类用于 Symfony 项目。并希望以与

相同的方式工作

由于您已经包含了我之前对您的 OP 的几乎所有答案,因此我发布了一些我对 laravel Mailer 类所做的修改,以使其正常工作以及为什么需要它。

这是Mailer.php的原始代码

/**
 * Send a new message using a view.
 *
 * @param  string|array  $view
 * @param  array  $data
 * @param  \Closure|string  $callback
 * @return mixed
 */
public function send($view, array $data, $callback)
{
    // First we need to parse the view, which could either be a string or an array
    // containing both an HTML and plain text versions of the view which should
    // be used when sending an e-mail. We will extract both of them out here.
    list($view, $plain, $raw) = $this->parseView($view);

    $data['message'] = $message = $this->createMessage();

    $this->callMessageBuilder($callback, $message);

    // Once we have retrieved the view content for the e-mail we will set the body
    // of this message using the HTML type, which will provide a simple wrapper
    // to creating view based emails that are able to receive arrays of data.
    $this->addContent($message, $view, $plain, $raw, $data);

    $message = $message->getSwiftMessage();

    return $this->sendSwiftMessage($message);
}

正如您所见,即使在回调之后,laravel 也在对消息进行一些黑魔法,这对我们不利。现在,如果我们更深入地研究黑魔法函数addContent,那么您将看到内容类型是由我们在最初调用视图类时发送的参数类型强制的:

/**
 * Add the content to a given message.
 *
 * @param  \Illuminate\Mail\Message  $message
 * @param  string  $view
 * @param  string  $plain
 * @param  string  $raw
 * @param  array   $data
 * @return void
 */
protected function addContent($message, $view, $plain, $raw, $data)
{
    if (isset($view))
    {
        $message->setBody($this->getView($view, $data), 'text/html');
    }

    if (isset($plain))
    {
        $message->addPart($this->getView($plain, $data), 'text/plain');
    }

    if (isset($raw))
    {
        $message->addPart($raw, 'text/plain');
    }
}

现在为了缓解这个问题,我建议你将原来的 Mailer 类扩展到你的命名空间,然后交换包含 addContentcallMessageBuilder 的行,然后在 laravel 的问题跟踪器上创建一个问题,说明为什么会这样做派上用场。您的最终代码将如下所示:

 /**
 * Send a new message using a view.
 *
 * @param  string|array  $view
 * @param  array  $data
 * @param  \Closure|string  $callback
 * @return mixed
 */
public function send($view, array $data, $callback)
{
    // First we need to parse the view, which could either be a string or an array
    // containing both an HTML and plain text versions of the view which should
    // be used when sending an e-mail. We will extract both of them out here.
    list($view, $plain, $raw) = $this->parseView($view);

    $data['message'] = $message = $this->createMessage();

    // Once we have retrieved the view content for the e-mail we will set the body
    // of this message using the HTML type, which will provide a simple wrapper
    // to creating view based emails that are able to receive arrays of data.
    $this->addContent($message, $view, $plain, $raw, $data);

    $this->callMessageBuilder($callback, $message);

    $message = $message->getSwiftMessage();

    return $this->sendSwiftMessage($message);
}

您的控制器中的代码将如下所示:

\Mail::send('nada', array(), function($message) use($icalendar)
{
    $message->from('from@email.com', 'Arun Poudel');
    $message->to('to@email.com')->subject('Test Calendar Event');

    $encoder = \Swift_Encoding::get7BitEncoding();
    $message->setEncoder($encoder);

    $message->addPart($icalendar, 'text/calendar; method=REQUEST', 'iso-8859-1');
});

注意:此代码适用于 gmail 的电子邮件,也适用于 OSX 上的 Outlook 14.0,如果您需要其他帮助,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多