I'm using Bolt 4 (based on Symfony 5), and have a custom Controller which has a function that sends an email when a new event is added. I attach to this email an *.ics calendar file. Unfortunately, this file is only seen as an attachement: client such as Gmail or Outlook only sees an email with a file attachement, and not a meeting request.
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Address;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
use Bolt\Entity\User;
use Bolt\Repository\UserRepository;
private function sendEmail(MailerInterface $mailer, $title, $datetime, $event_id)
{
// Generate the date time string
setlocale(LC_ALL, 'fr_FR');
$date = utf8_encode(strftime("%A %e %B, %Hh%M", strtotime($datetime)));
$meetingStartTime = strtotime($datetime);
$meetingEndTime = strtotime($datetime) + 60*60*2;
// Create the ics file
$fs = new Filesystem();
//temporary folder, it has to be writable
$tmpFolder = $this->getParameter('kernel.project_dir') . '/tmp/';
//the name of your file to attach
$fileName = 'meeting.ics';
$icsContent = "
BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VEVENT
DTSTART:".date('Ymd\THis', strtotime($meetingStartTime))."
DTEND:".date('Ymd\THis', strtotime($meetingEndTime))."
DTSTAMP:".date('Ymd\THis', strtotime($meetingStartTime))."
ORGANIZER;CN=XYZ:mailto:do-not-reply@example.com
UID:".rand(5, 1500)."
ATTENDEE;PARTSTAT=NEEDS-ACTION;RSVP= TRUE;CN=Sample:emailaddress@testemail.com
DESCRIPTION:".$title." requested Phone/Video Meeting Request
LOCATION: Phone/Video
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Meeting summary
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR"
;
//creation of the file on the server
$icfFile = $fs->dumpFile($tmpFolder.$fileName, $icsContent);
// Loop over the users
$userRepository = $this->getDoctrine()->getRepository(User::class);
$users = $userRepository->findAll();
foreach($users as $user) {
$email = (new TemplatedEmail())
->from(new Address('example@email.com', 'Name'))
->to($user->getEmail())
->htmlTemplate('email_template.twig')
->context([
'display_name' => $user->getDisplayName(),
'title' => $title,
'date' => $date,
'event_id' => $event_id
])
->subject($title)
->attachFromPath($tmpFolder.$fileName, null, 'text/calendar');
$mailer->send($email);
}
//remove the created file
$fs->remove(array('file', $tmpFolder, $fileName));
}
By comparing an *.eml generated by Outlook, and the *.eml this function generates, I observe this difference:
Email generated by the above code:
...
Content-Type: text/calendar; name=meeting.ics
...
Email generated by Outlook:
...
Content-Type: text/calendar; charset="utf-8"; method=REQUEST
...
Thank you in advance for your help!