Sincronizando eventos entre contas do Outlook usando Python

Olá pessoal! Neste texto eu vou demonstrar uma forma de criar um script em Python para sincronizar eventos entre duas contas do Outlook usando a lib PyExchange.

O código completo pode ser baixado aqui.

A primeira coisa a ser feita é instalar o PyExchange e para isso vamos utilizar o pip:

pip install pyexchange

O próximo passo é começar o script importando os módulos que serão necessários:

from datetime import datetime
from pytz import timezone
from pyexchange import Exchange2010Service, ExchangeNTLMAuthConnection

Então, devemos configurar os dados da conta de origem:

originURL = u'nomeDoServidor.outlook.com/EWS/Exchange.asmx'
originUsername = u'nomeDoUsuario'
originPassword = u"passwordDoUsuario"

Note que na URL sempre devemos incluir o sufixo “/EWS/Exchange.asmx”.

Após definir os dados da conta, podemos configurar a conexão e iniciar o serviço usando a lib PyExchange:

originConnection = ExchangeNTLMAuthConnection(url=originURL, username=originUsername, password=originPassword)
originService = Exchange2010Service(originConnection)

Com o serviço instanciado, só falta obter uma instância do calendário e listar todos os eventos, conforme nosso filtro:

originCalendar = originService.calendar()originEvents = originCalendar.list_events(
start=timezone("America/Sao_Paulo").localize(datetime(2017, 11, 1, 0, 0, 0)),
end=timezone("America/Sao_Paulo").localize(datetime(2017, 11, 17, 0, 0, 0)),
details=True
)

No exemplo acima, estou listando todos os eventos entre 01/11/2017 e 17/11/2017 no timezone de São Paulo.

Dando continuidade, criei uma classe chamada Event para armazenar os dados dos nossos eventos. Não se esqueça de adicionar a linha abaixo no início para importar a classe:

from Event import Event

Note que na classe Event foi preciso implementar o método __eq__ para verificarmos se os eventos são iguais:

class Event:
def __init__(self, start, end, subject, location, html_body, text_body, attendees, required_attendees, optional_attendees, recurrence, recurrence_interval, recurrence_end_date, recurrence_days):
self.start = start
self.end = end
self.subject = subject
self.location = location
self.html_body = html_body
self.text_body = text_body
self.attendees = attendees
self.required_attendees = required_attendees
self.optional_attendees = optional_attendees
self.recurrence = recurrence
self.recurrence_interval = recurrence_interval
self.recurrence_end_date = recurrence_end_date
self.recurrence_days = recurrence_days

def __eq__(self, other):
return self.start == other.start and self.end == other.end \
and self.subject == other.subject and self.location == other.location \
and self.html_body == other.html_body and self.text_body == other.text_body \
and self.attendees == other.attendees and self.required_attendees == other.required_attendees \
and self.optional_attendees == other.optional_attendees and self.recurrence == other.recurrence \
and self.recurrence_interval == other.recurrence_interval and self.recurrence_end_date == other.recurrence_end_date \
and self.recurrence_days == other.recurrence_days

O código abaixo cria uma lista de eventos e imprime no console algumas informações sobre os itens inseridos:

originList = list()
for originEvent in originEvents.events:
event = Event(originEvent.start, originEvent.end, originEvent.subject, originEvent.location, originEvent.html_body, originEvent.text_body, originEvent.attendees, originEvent.required_attendees, originEvent.optional_attendees, originEvent.recurrence, originEvent.recurrence_interval, originEvent.recurrence_end_date, originEvent.recurrence_days)
originList.append(event);
print "{start} {end} - {subject}".format(
start=originEvent.start,
end=originEvent.end,
subject=originEvent.subject
)

Agora que já temos os eventos da primeira conta do Outlook, vamos pegar os eventos da segunda conta da mesma forma:

destinyURL = u'https://outroServidor.outlook.com/EWS/Exchange.asmx'
destinyUsername = u'nomeUsuario'
originPassword = u'passwordUsuario'

# Set up the connection to Exchange
destinyConnection = ExchangeNTLMAuthConnection(url=destinyURL,
username=destinyUsername,
password=originPassword)

destinyService = Exchange2010Service(destinyConnection)

destinyCalendar = destinyService.calendar()

destinyEvents = destinyCalendar.list_events(
start=timezone("America/Sao_Paulo").localize(datetime(2017, 11, 1, 0, 0, 0)),
end=timezone("America/Sao_Paulo").localize(datetime(2017, 11, 17, 0, 0, 0)),
details=True
)

destinyList = list()
for destinyEvent in destinyEvents.events:
event = Event(destinyEvent.start, destinyEvent.end, destinyEvent.subject, destinyEvent.location, destinyEvent.html_body, destinyEvent.text_body, destinyEvent.attendees, destinyEvent.required_attendees, destinyEvent.optional_attendees, destinyEvent.recurrence, destinyEvent.recurrence_interval, destinyEvent.recurrence_end_date, destinyEvent.recurrence_days)
destinyList.append(event);
print "{start} {end} - {subject}".format(
start=destinyEvent.start,
end=destinyEvent.end,
subject=destinyEvent.subject
)

Com as duas listas de eventos prontas, como faço para saber quais eventos devo incluir? A forma que eu encontrei foi a seguinte:

Iterar a lista de origem e para cada ocorrência verificar se o evento está na lista de destino. Caso não esteja, basta usar os métodos da PyExchange para criar o evento:

for event in originList:
if event not in destinyList:
event = destinyService.calendar().new_event(
subject=originEvent.subject,
start=originEvent.start,
end=originEvent.end,
location=originEvent.location,
html_body = originEvent.html_body,
text_body = originEvent.text_body,
recurrence = originEvent.recurrence,
recurrence_interval = originEvent.recurrence_interval,
recurrence_end_date = originEvent.recurrence_end_date,
recurrence_days = originEvent.recurrence_days
)
event.create()

O mesmo procedimento deve ser feito para incluirmos os eventos da lista de destino na lista de origem:

event = originService.calendar().new_event(
subject=destinyEvent.subject,
start=destinyEvent.start,
end=destinyEvent.end,
location=destinyEvent.location,
html_body = destinyEvent.html_body,
text_body = destinyEvent.text_body,
recurrence = destinyEvent.recurrence,
recurrence_interval = destinyEvent.recurrence_interval,
recurrence_end_date = destinyEvent.recurrence_end_date,
recurrence_days = destinyEvent.recurrence_days
)
event.create()

Pronto! Dessa forma nossa agenda de eventos está sincronizada entre duas contas do Outlook.

Se você tiver alguma sugestão de melhoria, deixe seu comentário e vamos trocar uma ideia a respeito.