Managing Appointments in Python
Creating and Saving Appointments
The Appointment class in Aspose.Email API can be used to load an appointment in ICS format as well as create a new one and save it to disk in ICS format.
Create an Appointment and Save as ICS
The following code snippets shows you how to create and save an appointment to disk in ICS format:
- Create an instance of MailAddressCollection to store email addresses of the attendees and add an attendee’s email to the MailAddressCollection using the
append()method. - Use the Appointment constructor to create a new appointment with details such as location, start time, end date, organizer email, and list of attendees.
- Set appointment properties - summary and description - to describe the meeting specifics.
- Save the appointment in ICS format using the save() method specifying the file path and the format.
The appointment can be opened in Microsoft Outlook or any program that can load an ICS file. If the file is opened in Microsoft Outlook it automatically adds the appointment in the Outlook calendar.
Create an Appointment with HTML Content
You can specify alternative representations of the event description in different content types using the X-ALT-DESC header. It allows the recipients of the iCalendar file to choose the representation that best suits their needs. For example, you may include a plain text description with the text/plain content type and an HTML description with the text/html content type. The X-ALT-DESC header is added for each alternative representation.
To create an appointment with HTML content, set the html_description property of the Appointment class:
import datetime
import aspose.email as ae
from aspose.email.calendar import Appointment
attendees = ae.MailAddressCollection()
attendees.append(ae.MailAddress("AinaMartensson@to.com", "Aina Martensson"))
appointment = Appointment(
"Bygget 83", # location
datetime.datetime.utcnow(), # start date
datetime.datetime.utcnow() + datetime.timedelta(hours=1), # end date
ae.MailAddress("TintinStrom@from.com", "Tintin Strom"), # organizer
attendees)
appointment.html_description = """
<html>
<style type="text/css">
.text {
font-family:'Comic Sans MS';
font-size:16px;
}
</style>
<body>
<p class="text">Hi, I'm happy to invite you to our party.</p>
</body>
</html>"""
appointment.save("appointment_with_html.ics")
Customize the Product Identifier for iCalendar
Aspose.Email allows you to get or set the identifier of the product that created the iCalendar object. Use the product_id property of the AppointmentIcsSaveOptions class:
import datetime
import aspose.email as ae
from aspose.email.calendar import Appointment, AppointmentIcsSaveOptions
attendees = ae.MailAddressCollection()
attendees.append(ae.MailAddress("second@test.com"))
app = Appointment("location",
datetime.datetime.today(),
datetime.datetime.today() + datetime.timedelta(days=1),
ae.MailAddress("first@test.com"),
attendees)
app.summary = "test appointment"
app.description = "Test Description"
save_options = AppointmentIcsSaveOptions()
save_options.product_id = "Test Corporation"
app.save("ChangeProdIdOfICS.ics", save_options)
Create a Draft Appointment Request
It is often required to create an Appointment request in Draft mode, so as the basic information is added and then the same draft Appointment can be forwarded to other users for necessary changes according to individual requests. In order to save an Appointment in Draft mode, the method_type property of Appointment class should be set to ‘publish’. The following code snippet shows you how to create a draft appointment request.
Draft Appointment from Text
The following code snippet shows you how to create a draft appointment from Text.
Loading and Reading Appointments
Load Appointments from ICS Files
The following code snippet shows you how to load an appointment in ICS format:
- Use the Appointment.load() method to load an appointment from an existing ICS file specifying the path.
- Retrieve and display appointment details: summary, location, description, start date, end date, organizer, and attendees.
Convert ICS to MSG
The API allows you to easily convert an appointment into a message object. The following code sample shows how to convert an appointment request into a MailMessage or a MapiMessage:
from aspose.email.calendar import Appointment
appointment = Appointment.load("appRequest.ics")
eml = appointment.to_mail_message()
msg = appointment.to_mapi_message()
Determine the Appointment Version
To determine the version of an appointment, use the version property of the Appointment class. It helps to determine which version your files are based on, which makes the integration with other systems and apps easier. The property is a string that holds the ICS/VCS version — "2.0" for iCalendar, for example.
from aspose.email.calendar import Appointment
app = Appointment.load("meeting.ics")
if app.version == "2.0":
# do something
print("iCalendar 2.0")
Read Multiple Events from ICS Files
With Aspose.Email, you can read all the events from a given ICS file and store them in a list, then output the total number of appointments. The following code sample demonstrates how to perform this task:
- Use the CalendarReader class to initialize a reader that will process an ICS file containing calendar events. Specify the location of the ICS file in the constructor.
- Create an empty list named ‘appointments’ to store the events read from the ICS file.
- Iterate through each event in the ICS file using the reader.next_event().
- Append the current event (reader.current) to the appointments list.
- Print the total number of appointments.
Writing and Updating Appointments
Write Multiple Events to ICS Files
Create and save multiple events into an ICS file, with each event containing specific details, such as attendees, location, time, and descriptive information. The following code sample will show you how to create and save multiple appointment events into an ICS calendar file:
- Create an instance of IcsSaveOptions to specify how the calendar events will be saved.
- Set the action property to AppointmentAction.CREATE to indicate that the appointments should be created in the ICS file.
- Use the CalendarWriter class to set up a writer for outputting events into an ICS file providing the output file path and the previously defined save options.
- Create a MailAddressCollection to manage the list of attendees for each appointment. Add a specific email address to this collection using the append method.
- Iterate 10 times using a for loop, corresponding to the creation of 10 appointment events. For each iteration, create an Appointment instance with specified details such as location, start time, end date, organizer email, and attendees.
- Add event details: description and summary properties.
- Use the write method of the writer to output the appointment to the ICS file.
Set Participant Status for Appointment Attendees
Aspose.Email for .NET API allows you to set the statuses of the appointment attendees while formulating a reply message. By assigning these statuses to each attendee, the application or system working with the Appointment object can handle event-related logic, such as showing confirmed attendees, tracking changes, or managing notifications accordingly.
Sending and Cancelling Meeting Requests
The Appointment class, together with the SmtpClient, can be used to send meeting requests, recurring meeting requests, updates and cancellations by email. The appointment is added to a MailMessage as an alternate view.
Send a Meeting Request
To send a meeting request, create an appointment, add it to a message with the request_apointment() method and send the message. Save the unique_id value of the appointment so that you can reference the same appointment later when sending an update or a cancellation.
import datetime
import aspose.email as ae
from aspose.email.calendar import Appointment
from aspose.email.clients.smtp import SmtpClient
# Create an instance of SmtpClient
client = SmtpClient("smtp.gmail.com", 587, "user@gmail.com", "password")
client.security_options = ae.clients.SecurityOptions.AUTO
# Gather the attendees
attendees = ae.MailAddressCollection()
attendees.append(ae.MailAddress("first.attendee@domain.com", "First Attendee"))
attendees.append(ae.MailAddress("second.attendee@domain.com", "Second Attendee"))
# Create the message and the appointment
msg = ae.MailMessage()
msg.from_address = ae.MailAddress("organizer@domain.com")
msg.to = attendees
app = Appointment("Meeting Room 1",
datetime.datetime.now(),
datetime.datetime.now() + datetime.timedelta(hours=1),
msg.from_address, attendees)
app.summary = "Monthly Meeting"
app.description = "Please confirm your availability."
# Add the appointment to the message and send it
msg.add_alternate_view(app.request_apointment())
client.send(msg)
Send a Recurring Meeting Request
To create a meeting request with recurrence, assign a recurrence pattern — a WeeklyRecurrencePattern, for example — to the recurrence property of the appointment. Saving the unique id of the appointment makes it possible to send updates to it later.
import datetime
import uuid
import aspose.email as ae
from aspose.email.calendar import Appointment
from aspose.email.calendar.recurrences import WeeklyRecurrencePattern, CalendarDay
# Create a mail message
msg = ae.MailMessage()
msg.to.append(ae.MailAddress("to@domain.com"))
msg.from_address = ae.MailAddress("from@gmail.com")
# Fill the appointment object
start_date = datetime.datetime(2025, 12, 1, 17, 0, 0)
end_date = datetime.datetime(2025, 12, 31, 17, 30, 0)
agenda_appointment = Appointment("same place", start_date, end_date, msg.from_address, msg.to)
# Create a unique id so that the appointment can be accessed later
unique_id = str(uuid.uuid4())
agenda_appointment.unique_id = unique_id
agenda_appointment.description = "----------------"
# Create a weekly recurrence pattern: Mon, Tue and Thu
pattern = WeeklyRecurrencePattern(14)
pattern.start_days = [CalendarDay.MONDAY, CalendarDay.TUESDAY, CalendarDay.THURSDAY]
pattern.interval = 1
# Set the recurrence pattern for the appointment
agenda_appointment.recurrence = pattern
# Attach the appointment to the mail
msg.alternate_views.append(agenda_appointment.request_apointment())
msg.save("recurring_request.eml", ae.SaveOptions.default_eml)
Send an Appointment Update Request
To send an update for a previously sent appointment, its unique id is required. Use the update_appointment() method to build the update alternate view:
import datetime
import aspose.email as ae
from aspose.email.calendar import Appointment
unique_id = "the id stored when the request was sent"
start_date = datetime.datetime(2025, 12, 12, 17, 0, 0)
end_date = datetime.datetime(2025, 12, 12, 17, 30, 0)
attendees = ae.MailAddressCollection()
attendees.append(ae.MailAddress("attendee@domain.com"))
app_update = Appointment("Different Place", start_date, end_date,
ae.MailAddress("organizer@gmail.com"), attendees)
app_update.unique_id = unique_id
app_update.summary = "update meeting request summary"
app_update.description = "update"
msg_update = ae.MailMessage("organizer@gmail.com", "attendee@domain.com",
"test email - update meeting request", "test email")
msg_update.add_alternate_view(app_update.update_appointment())
msg_update.save("meeting_update.eml", ae.SaveOptions.default_eml)
Cancel a Meeting Request
To cancel a meeting, build the same appointment from the information you stored when the request was sent, add it to a message with the cancel_appointment() method and send the message to the attendees:
import datetime
import aspose.email as ae
from aspose.email.calendar import Appointment
# Re-create the attendee collection and the appointment from your stored data
attendees = ae.MailAddressCollection()
attendees.append(ae.MailAddress("first.attendee@domain.com", "First Attendee"))
attendees.append(ae.MailAddress("second.attendee@domain.com", "Second Attendee"))
app = Appointment("Meeting Room 1",
datetime.datetime.now(),
datetime.datetime.now() + datetime.timedelta(hours=1),
ae.MailAddress("organizer@domain.com", "Organizer"), attendees)
app.summary = "Monthly Meeting"
app.description = "Please confirm your availability."
# Create the cancellation message
msg = ae.MailMessage()
msg.from_address = ae.MailAddress("organizer@domain.com")
msg.to = attendees
msg.subject = "Cancel meeting"
msg.add_alternate_view(app.cancel_appointment())
msg.save("meeting_cancellation.eml", ae.SaveOptions.default_eml)
Working with iCalendar Recurrence Patterns
A recurrence pattern is a way to describe a particular schedule. It contains just enough information to build a list of occurrences (dates and times) according to a given schedule. A recurrence pattern may contain recurrence rules that describe cycles that combine to form the overall pattern. In general, the more complex a recurrence pattern is, the more recurrence rules it contains.
Recurrence patterns can include exceptions. Exceptions add or remove occurrence dates relative to the original pattern. They can be specified as explicit occurrences or as a pattern themselves. Examples of recurrence patterns with exceptions:
- Every 2nd Friday, except from June through August.
- The 1st of every month, except for January, when it should be on the 2nd.
The recurrence pattern properties defined by iCalendar are:
- DTSTART – the start date and time of the pattern (it also represents the first occurrence if it is not excluded explicitly).
- RRULE – specifies a repeating rule for a recurrence set.
- RDATE – defines a list of dates and times to include in a recurrence set.
- EXRULE – specifies a repeating rule for exceptions from a recurrence set.
- EXDATE – defines a list of date and time exceptions from a recurrence set.
Only DTSTART is required, and there must be only one DTSTART. All the other properties are optional and can be specified more than once.
The Aspose.Email Recurrence Object Model
The aspose.email.calendar.recurrences module contains the classes used to work with iCalendar recurrences. CalendarRecurrence and RecurrenceRule are the central classes.
- The
CalendarRecurrenceclass represents the whole recurrence pattern. You can create a new pattern from scratch using the default constructor, or build one from an existing iCalendar string by passing it to the constructor. - The
RecurrenceRuleclass represents the RRULE or EXRULE part of a recurrence pattern. Its properties map directly to their counterparts in the iCalendar standard —by_monthmaps to BYMONTH, and so on.
The following code snippet loads a recurrence pattern and generates the occurrences:
from aspose.email.calendar.recurrences import CalendarRecurrence
# Ten team meetings, every Monday at 10am
pattern = CalendarRecurrence("DTSTART:20040301T100000\nRRULE:FREQ=WEEKLY;COUNT=10;BYDAY=MO")
dates = pattern.generate_occurrences()
for date in dates:
print(date)
Generate Occurrences from a Recurrence Pattern
To get the “next” occurrence, call generate_occurrences with the argument 1. The following code snippet builds a pattern programmatically and generates 20 occurrences:
import datetime
from aspose.email.calendar.recurrences import CalendarRecurrence, Frequency
recurrence_pattern = CalendarRecurrence()
recurrence_pattern.start_date = datetime.datetime(1997, 9, 10, 9, 0, 0)
rule = recurrence_pattern.r_rules.add()
rule.frequency = Frequency.MONTHLY
rule.count = 20
rule.interval = 18
rule.by_month_day.add([10, 11, 12, 13, 14, 15])
expected_dates = recurrence_pattern.generate_occurrences(20)
print("expected_dates count = " + str(len(expected_dates)))
for date in expected_dates:
print("DateTime = " + str(date))
Get User-Friendly Text for a Recurrence
User-friendly text for a rule is available through the friendly_text property. The output of the following code is: “Recur every month on the 1st and 1st from end day(s) of the month for a maximum of 2 occurrences.”
from aspose.email.calendar.recurrences import RecurrenceRule, Frequency
rule = RecurrenceRule()
rule.frequency = Frequency.MONTHLY
rule.count = 2
rule.by_month_day.add(1)
rule.by_month_day.add(-1)
print(rule.friendly_text)
Sample Recurrence Patterns
The following sample RRULE strings illustrate how to express common schedules.
-
The last day of the month, every month. If you want an occurrence on the day before the last day of the month, use
BYMONTHDAY=-2. If you specifyBYMONTHDAY=31, then according to the iCalendar standard no occurrence is generated in the months that have fewer than 31 days.RRULE:FREQ=MONTHLY;BYMONTHDAY=-1 -
The last workday of every month. This rule specifies all the workdays of a month and selects the last one.
RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1 -
The last Monday of the year.
RRULE:FREQ=YEARLY;BYDAY=-1MO -
Friday of the first ISO 8601 week of the year. In the ISO 8601 specification, the first week of the year is the first one with at least four days.
FREQ=YEARLY;BYWEEKNO=1;BYDAY=FR -
First Friday of the year. In 1999, for example, the 1st Friday of the year is 1999/01/01, while the Friday of the 1st ISO 8601 week is 1999/01/08.
FREQ=YEARLY;BYDAY=1FR
Important iCalendar (RFC 2445) Details
Dates, or dates with associated times, can be used in the DTSTART, UNTIL, EXDATE and RDATE elements when specifying a recurrence pattern. iCalendar defines the DATE value type to identify the values that contain a calendar date, and the DATE-TIME type to identify the values that specify a precise calendar date and time of day. DATE-TIME values can be specified in three forms: local time, UTC time, and local time with a time zone.
- DATE. According to the iCalendar standard, DATE values must follow the
yyyyMMddformat. For example,19970714represents July 14, 1997. - DATE-TIME with local time. The date with local time form is a date-time value that does not contain the UTC designator and does not reference a time zone. For example,
DTSTART:19980118T230000represents January 18, 1998, at 11 PM. Date-time values of this type are said to be “floating” and are not bound to any particular time zone. - DATE-TIME with UTC time. The date with UTC time (absolute time) is identified by a capital letter
Zsuffix appended to the time value. For example,DTSTART:19980119T070000Zrepresents January 19, 1998, at 0700 UTC. Note that Aspose.Email ignores the UTCZsuffix and treats the time as local time. The RFC 2445 standard states that a time portion specified in the UNTIL rule of a recurrence pattern must be in UTC format; Aspose.Email accepts time in any format in the UNTIL rule. - DATE-TIME with local time and time zone. To reference a time zone, DATE-TIME is modified with the TZID property. For example,
DTSTART;TZID=US-Eastern:19980119T020000represents 2 AM in New York on January 19, 1998. Note that Aspose.Email currently ignores the TZID parameter and treats the time as local time. - BYWEEKNO and ISO 8601 compliance. Use BYWEEKNO only when conformance with ISO 8601 is required. Week numbers as defined by ISO 8601 differ from week numbers in the normal sense: week number one of the calendar year is the first week that contains at least four days. The BYWEEKNO rule specifies a comma-delimited list of numbers identifying the weeks of the year (valid values are 1 to 53 and -1 to -53), and it is only valid for YEARLY rules.
See Also
- Managing Outlook Calendar Items — create and manage calendar items as Outlook
MapiCalendar(MSG) objects. - Managing Recurrences — build MAPI recurrence patterns for tasks and calendar items.