Sending Outlook appointments with Python

Python allows you to send calendar appointments (invitations / events) directly from your code. It is quite easy to create a new appointment in the standard iCalendar format (ics). You can do it by hand or use a convenient icalendar open source module. In order to convince Outlook, however, to present the iCalendar events as native calendar appointments, you will need to make some effort. Fortunately, other people have already collected all the necessary pieces. Below is a working example for sending Outlook-friendly invitation from Python. In principle, you could use some of the information here to send similar invitation using different API, for example .NET.

Note, that you need to supply the relevant timezone information with your dates, otherwise the result might be different from what you expect.

  1. import email.MIMEText
  2. import email.MIMEBase
  3. from email.MIMEMultipart import MIMEMultipart
  4. import smtplib
  5. import datetime as dt
  6. import icalendar
  7. import pytz
  8.  
  9. def sendAppointment(self, subj, description):
  10.   # Timezone to use for our dates - change as needed
  11.   tz = pytz.timezone("Europe/London")
  12.   reminderHours = 1
  13.   startHour = 7
  14.   start = tz.localize(dt.datetime.combine(self.date, dt.time(startHour, 0, 0)))
  15.   cal = icalendar.Calendar()
  16.   cal.add('prodid', '-//My calendar application//example.com//')
  17.   cal.add('version', '2.0')
  18.   cal.add('method', "REQUEST")
  19.   event = icalendar.Event()
  20.   event.add('attendee', self.getEmail())
  21.   event.add('organizer', "me@example.com")
  22.   event.add('status', "confirmed")
  23.   event.add('category', "Event")
  24.   event.add('summary', subj)
  25.   event.add('description', description)
  26.   event.add('location', "Room 101")
  27.   event.add('dtstart', start)
  28.   event.add('dtend', tz.localize(dt.datetime.combine(self.date, dt.time(startHour + 1, 0, 0))))
  29.   event.add('dtstamp', tz.localize(dt.datetime.combine(self.date, dt.time(6, 0, 0))))
  30.   event['uid'] = getUniqueId() # Generate some unique ID
  31.   event.add('priority', 5)
  32.   event.add('sequence', 1)
  33.   event.add('created', tz.localize(dt.datetime.now()))
  34.  
  35.   alarm = icalendar.Alarm()
  36.   alarm.add("action", "DISPLAY")
  37.   alarm.add('description', "Reminder")
  38.   #alarm.add("trigger", dt.timedelta(hours=-reminderHours))
  39.   # The only way to convince Outlook to do it correctly
  40.   alarm.add("TRIGGER;RELATED=START", "-PT{0}H".format(reminderHours))
  41.   event.add_component(alarm)
  42.   cal.add_component(event)
  43.  
  44.   msg = MIMEMultipart("alternative")
  45.  
  46.   msg["Subject"] = subj
  47.   msg["From"] = "{0}@example.com".format(self.creator)
  48.   msg["To"] = self.getEmail()
  49.   msg["Content-class"] = "urn:content-classes:calendarmessage"
  50.  
  51.   msg.attach(email.MIMEText.MIMEText(description))
  52.  
  53.   filename = "invite.ics"
  54.   part = email.MIMEBase.MIMEBase('text', "calendar", method="REQUEST", name=filename)
  55.   part.set_payload( cal.to_ical() )
  56.   email.Encoders.encode_base64(part)
  57.   part.add_header('Content-Description', filename)
  58.   part.add_header("Content-class", "urn:content-classes:calendarmessage")
  59.   part.add_header("Filename", filename)
  60.   part.add_header("Path", filename)
  61.   msg.attach(part)
  62.  
  63.   s = smtplib.SMTP('localhost')
  64.   s.sendmail(msg["From"], [msg["To"]], msg.as_string())
  65.   s.quit()

Cancelling an existing event

You can send a cancel for an existing appointment as well. In order to do this, change method in both places in the code above from REQUEST to CANCEL, and set status</status> to <code>CANCELLED. You must ensure you use the same id as you used to create your original event.

No-response events

If you don't want the appointment participant's Outlook to send you a reply when he or she accepts, you can use the following code:

  1. event.add("ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=FALSE", email)

5 Comments

I would like to use the

I would like to use the script but I am new to python. Could you add and example on how to use it. I am not sure how to specify the sender's email. I tried to setup a structure appointment and add to it the time which seems to work, but not sure how to add the email of the sender that is called using self.getEmail().

Thanks

My bad I meant to say the

My bad I meant to say the recipient email not the sender. I am not sure if there is an elegant way I can pass a list of recipients. Based on the code there is self.getEmail(). but I am not sure if getEmail() is something that exists or I have to create it.

Thanks

Add new comment

Subscribe to Comments for "Sending Outlook appointments with Python"