Sending Smart Invites

Required plan: Emerging

In order to have the invite understood correctly by the receiving mail server/client there are a couple of approaches to attaching them required. This ensures that, where supported, the user will also be presented with the Accept/Decline helpers in their email client.

For more detailed best practices, we recommend following the iMIP Best Practices for sending invites. This will guarantee the widest support.

# Using Rails

class SmartInviteMailer < ActionMailer::Base
  def invite(smart_invite)
    event_ics = smart_invite.attachments.icalendar

    method = 'REQUEST' # method=CANCEL in the case of cancellations

    attachments.inline["invite.ics"] = {
      content_type: "text/calendar; charset=UTF-8; method=#{method}",
      encoding: '7bit',
      content: event_ics,
    }

    attachments["invite.ics"] = {
      content_type: "application/ics; charset=UTF-8; method=#{method}",
      encoding: 'base64',
      content: Base64.encode64(event_ics),
    }

    invite_mail = mail(
      to: smart_invite.recipient.email,
      subject: "Smart Invite Example",
      body: "Here is your invite."
    )

    # In Rails >= 6, we need to change ActionMailers default inline attachment content-type
    # to match the iMIP best practices for sending calendar invites, so that Outlook can show
    # the Accept/Tentative/Decline buttons in line.
    invite_mail
      .parts
      .select { |part| contains_calendar_subpart?(part) }
      .each { |part| replace_multipart_type(part) }
  end

  private def contains_calendar_subpart?(part)
    part.parts.any? { |subpart| subpart.content_type.start_with? "text/calendar" }
  end

  private def replace_multipart_type(part)
    new_content_type = part.content_type.sub(%r{multipart/[\w]+}, "multipart/alternative")
    part.content_type = new_content_type
    part
  end
end
// Using the https://github.com/PHPMailer/PHPMailer script

require '../vendor/autoload.php';

$mail = new PHPMailer();

$mail->setFrom('application@example.com');
$mail->addAddress($invite->recipient->email);
$mail->Subject = 'Smart Invite Example';
$mail->Body = 'Here is your invite';

$ics = $invite->attachments->icalendar;

$method = 'REQUEST' // method=CANCEL in the case of cancellations

$mail->addAttachment($ics, 'invite.ics', '7bit', "text/calendar; charset=UTF-8; method=$method", 'inline');
$mail->addAttachment(base64_encode($ics), 'invite.ics', 'base64', "application/ics; charset=UTF-8; method=$method", 'attachment');

$mail->send();
// Using the https://nodemailer.com/about/ library

const nodemailer = require('../lib/nodemailer');

// TODO configure transport as required
let transporter = nodemailer.createTransport({});

let ics = invite.attachments.icalendar;

let method = 'REQUEST'; // method=CANCEL in the case of cancellations

let message = {
    to: invite.recipient.email,
    subject: 'Smart Invite Example',
    text: 'Here is your invite',
    attachments: [
        {
            filename: 'invite.ics',
            content: ics,
            contentType: `text/calendar; charset=UTF-8; method=${method}`,
            contentDisposition: 'inline'
        },
        {
            filename: 'invite.ics',
            content: Buffer.from(ics, 'base64'),
            contentType: `application/ics; charset=UTF-8; method=${method}`,
            encoding: 'base64'
        },
    ]
};

transporter.sendMail(message, (error, info) => {
    transporter.close();
});
var message = new MailMessage("application@example.com", invite.Recipient.Email);
message.Subject = "Smart Invite Example";
message.Body = "Here is your invite";

var ics = invite.Attachments.ICalendar;

var method = "REQUEST"; // method=CANCEL in the case of cancellations

var inlineAttachment = new Attachment(
    new MemoryStream(Encoding.UTF8.GetBytes(ics)),
    "invite.ics",
    $"text/calendar; charset=UTF-8; method={method}"
);
inlineAttachment.ContentDisposition.Inline = true;

var attachment = new Attachment(
    new MemoryStream(Encoding.UTF8.GetBytes(ics)),
    "invite.ics",
    $"application/ics; charset=UTF-8; method={method}"
);

message.Attachments.Add(inlineAttachment);
message.Attachments.Add(attachment);