Update, you can use the live application here!
Recently I was tasked with the job of creating an application that would create and send calendar invites to a users email.
On the surface it seemed like a very simple build, send an email, attach a calendar invite. Done. Right?
Not so much, here’s the run down of how I accomplished it.
- SwiftMailer – http://swiftmailer.org/
- Sabre VObject – https://github.com/fruux/sabre-vobject
- Mailgun – http://mailgun.com/
The first step was to get Mailgun setup and working. It was SUPER easy to get started with and start sending mail. I’m a big fan of the service because they have lots of documentation tailored per language, as well as all the fun analytics for mail deliveries, opens and bounces/errors. Very easy to see how your app is running from a mail perspective. It only started to cost us ($89/month) when we wanted to have a custom sending domain for anti-SPAM reasons.
Rather than using the native sendmail() function, using a third-party email service allows for a better guaranteed sendability and general ease of development. Mail won’t get blocked as SPAM (as much) and it will generally send mail quicker.
Mailgun does provide an API, which I used at first, but I found that with custom attachments and MIME headers, it was much easier to use it as an SMTP service in conjunction with SwiftMailer.
|// Create the Transport|
|$transport = Swift_SmtpTransport::newInstance ( 'smtp.mailgun.org', 25 )|
|->setUsername ( 'firstname.lastname@example.org' )|
|->setPassword ( 'rand0mpa55' );|
|//Helps for sending mail locally during development|
|$transport->setLocalDomain ( '[127.0.0.1]' );|
|// Create the Mailer using your created Transport|
|$mailer = Swift_Mailer::newInstance ( $transport );|
Once Swiftmailer and Mailgun were all setup, it was time to create and attach the calendar event.
This was one of the more tricky parts since most of the docs and help I found on StackOverflow was manually mashing together things together as a string, then manually setting mail MIME headers. Gross.
Eventually I did run across the Sabre VObject project (https://github.com/fruux/sabre-vobject), and things went smoothly from there.
|//Using composer to get the Sabre lib|
|require dirname ( __FILE__ ) . '/../vendor/autoload.php';|
|// Create a message|
|$message = Swift_Message::newInstance ( 'Message Title' )|
|->setFrom ( array( 'email@example.com ' => 'John Doe' ) )|
|->setTo ( array( $email ) )|
|->setSubject ( "Cool message subject" )|
|->setBody ( $body )|
|->setContentType ( 'text/html' );|
|//Set the 'from' to something a bit nicer|
|$from = $message->getHeaders ()->get ( 'From' );|
|$from->setNameAddresses ( array(|
|'firstname.lastname@example.org ' => 'John Doe',|
|$headers = $message->getHeaders ();|
|//Add text header for Mailgun campaign tracking|
|$headers->addTextHeader ( 'X-Mailgun-Campaign-Id', '[mailgun-campaign-id]]' );|
|//Create calendar invite with Sabre VOject lib|
|$cal = new VCalendar();|
|//Create a meeting invite that lasts 2 hours on the same day|
|$vevent = $cal->add ( 'VEVENT', array(|
|'summary' => $subject,|
|'location' => 'Meeting room 1',|
|'dtstart' => new DateTime( $mtg_date . ' 09:00:00', new \DateTimeZone( 'America/Toronto' ) ),|
|'dtend' => new DateTime( $mtg_date . ' 11:00:00', new \DateTimeZone( 'America/Toronto' ) ),|
|'method' => 'REQUEST'|
|$data = $cal->serialize ();|
|$filename = "invite.ics";|
|//Attach the calendar invite to the mail|
|$attachment = Swift_Attachment::newInstance ()|
|->setFilename ( $filename )|
|->setContentType ( 'text/calendar' )|
|->setBody ( $data );|
|$message->attach ( $attachment );|
|$result = $mailer->send ( $message );|
And that’s pretty much it. Works well and tested accross multiple mail clients.