Outlook接受/拒绝按钮不会显示给Icalendar

时间:2015-04-28 11:54:40

标签: php email laravel swiftmailer

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

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

Calendar invitation

我的代码:

$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附件的电子邮件。我究竟做错了什么?为什么RSVP按钮没有出现?

2 个答案:

答案 0 :(得分:2)

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

$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

答案 1 :(得分:0)

  

注意:我之前发布的IcalendarUtil类用于a   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,如果您需要其他帮助,请与我们联系。