Adding "Add to calendar" buttons for multiple targets (Google, Outlook, iCal) to an email invitation
Last modified on July 24, 2026 • 4 min read • 760 words
This is more work than it should be in 2026. These were the first instructions that worked for me: https://www.litmus.com/blog/how-to-create-an-add-to-calendar-link-for-your-emails/ . The instructions essentially use hand-written code (and code generated with Amit Agarwal’s Calendar Links tool ( https://www.labnol.org/apps/calendar.html ).
However, there must be a Chrome plugin to do all this? Or a java script? The instructions are using a combination of different online tools, which makes the process tedious… Unfortunately, if all what I have read is correct, there is no good free solution (contact me if you know otherwise!). Even worse, there is no way to add an event automatically to Apple’s iCloud calendar short of importing an iCal file (which requires lots of manual clicking).
But both Google and Outlook accept calendar event data directly in the GET query parameters of the request URL (i.e. a simple html link or button that you can click). It is relatively easy to add buttons to an email that will open Google Calendar or Outlook and populate the respective calendar fields. As already mentioned, only Apple’s iCal still does not support this feature, and one workaround is to offer iCal file for download to import into iCal, although this requires you to have this file on some sort of server (Gdrive, OneDrive of DropBox would work as well).
But how can I get easily generate the buttons with the necessary code into an email in seconds when writing the email? My answer is: with Espanso! Espanso ( https://espanso.org/ ) listens to all your keystrokes and triggers certain events when it sees certain combinations, that you can freely define. I have assigned the “\cal” letters to a script that pops up a dialog with fields to enter “event”, “location”, “start date/time” and “end date/time”, and then inserts a button into my email client with the correct data. Again, Apple users have to download the .ical file and import it into iCalendar. Unfortunately, generating the iCal file and upload it to a server is way more work than it should be. You can use Amit Agarwal’s webtool to generate the file ( https://www.labnol.org/apps/calendar.html ), then upload it to a server or file sharing service of your choice and note down the URL to insert into the Espanso form. Also relativley easy - on Linux or Mac - is to upload the on-the-fly generated iCal file via scp to the server of your choice as done in the Espanso YAML configuration entry below. Note that the scp command uses passwordless authentication, which you need to setup!
- trigger: "/cal"
vars:
- name: form
type: form
params:
layout: |
Event Title (use %20 for spaces): [[title]]
Location (use %20 for spaces): [[loc]]
Date (YYYY-MM-DD): [[date]]
Start Time (HH:MM): [[start]]
End Time (HH:MM): [[end]]
- name: gdate
type: shell
params:
cmd: "echo '{{form.date}}' | tr -d '-'"
- name: gstart
type: shell
params:
cmd: "echo '{{form.start}}' | tr -d ':'"
- name: gend
type: shell
params:
cmd: "echo '{{form.end}}' | tr -d ':'"
- name: ics_filename
type: shell
params:
cmd: |
FILENAME="event_{{gdate}}_{{gstart}}.ics"
TITLE_CLEAN=$(echo '{{form.title}}' | sed 's/%20/ /g')
LOC_CLEAN=$(echo '{{form.loc}}' | sed 's/%20/ /g')
# Generate the iCal file locally
cat <<EOF > "/tmp/$FILENAME"
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//mjlab.fi//Espanso//EN
BEGIN:VEVENT
SUMMARY:$TITLE_CLEAN
DTSTART:{{gdate}}T{{gstart}}00
DTEND:{{gdate}}T{{gend}}00
LOCATION:$LOC_CLEAN
END:VEVENT
END:VCALENDAR
EOF
# Upload to your server (Uncomment and edit the path/user to match your server)
scp /tmp/$FILENAME user@mjlab.fi:/var/www/mjlab.fi/iCal/$FILENAME > /dev/null 2>&1
echo "$FILENAME"
html: |
<html>
<body>
<style>
.addToCalendar_google { background-color: #bf3f3f; border-radius: 28px; border: 1px solid #8f0e0e; display: inline-block; cursor: pointer; color: #ffffff; font-family: Arial, sans-serif; font-size: 16px; padding: 6px 12px; text-decoration: none; text-shadow: 0px 1px 0px #441515; margin: 5px; }
.addToCalendar_windows { background-color: #4981c1; border-radius: 28px; border: 1px solid #100f4e; display: inline-block; cursor: pointer; color: #ffffff; font-family: Arial, sans-serif; font-size: 16px; padding: 6px 12px; text-decoration: none; text-shadow: 0px 1px 0px #273066; margin: 5px; }
.addToCalendar_apple { background-color: #8f8f8f; border-radius: 28px; border: 1px solid #2c302c; display: inline-block; cursor: pointer; color: #ffffff; font-family: Arial, sans-serif; font-size: 16px; padding: 6px 12px; text-decoration: none; text-shadow: 0px 1px 0px #080c07; margin: 5px; }
.addToCalendar_google img, .addToCalendar_windows img, .addToCalendar_apple img { width: 20px; height: 20px; vertical-align: middle; border: none; }
.addToCalendar_google span, .addToCalendar_windows span, .addToCalendar_apple span { vertical-align: middle; padding-left: 12px; }
</style>
<a href="https://calendar.google.com/calendar/render?action=TEMPLATE&text={{form.title}}&dates={{gdate}}T{{gstart}}00/{{gdate}}T{{gend}}00&location={{form.loc}}" class="addToCalendar_google">
<img src="https://mjlab.fi/iCal/google.png" alt="Google" width="20" height="20" style="margin-right: 6px; vertical-align: middle; border: none;" />
<span>Add to Google Calendar</span>
</a>
<a href="https://outlook.office.com/calendar/0/action/compose?allday=false&subject={{form.title}}&startdt={{form.date}}T{{form.start}}:00&enddt={{form.date}}T{{form.end}}:00&location={{form.loc}}&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent" class="addToCalendar_windows">
<img src="https://mjlab.fi/iCal/windows.png" alt="Outlook" width="20" height="20" style="margin-right: 6px; vertical-align: middle; border: none;" />
<span>Add to MS Outlook</span>
</a>
<a href="https://mjlab.fi/iCal/{{ics_filename}}" class="addToCalendar_apple">
<img src="https://mjlab.fi/iCal/apple.png" alt="Apple" width="20" height="20" style="margin-right: 6px; vertical-align: middle; border: none;" />
<span>Add to Apple (iCal file)</span>
</a>
</body>
</html>