def outlook_calendar_event_exists(appointment, calendar_service, summary): ews_tz = EWSTimeZone.timezone('America/Chicago') d = appointment.start_time.datetime start_date_time = datetime(d.year, d.month, d.day, d.hour, d.minute, d.second, d.microsecond, ews_tz) start_ews_date_time = EWSDateTime.from_datetime(start_date_time) d = appointment.end_time.datetime end_date_time = datetime(d.year, d.month, d.day, d.hour, d.minute, d.second, d.microsecond, ews_tz) end_ews_date_time = EWSDateTime.from_datetime(end_date_time) matching_events = calendar_service.calendar.find_items( start=start_ews_date_time, end=end_ews_date_time, shape=AllProperties) if matching_events: for event in matching_events: if event.subject == summary: print( "Found a matching Outlook calendar event for appointment {app}. Will not create a new one.".format( app=appointment)) return True return False
def mail_ids_by_date( self, *, before: Optional[float] = None, after: Optional[float] = None, ) -> Iterable[float]: # exchangelib needs a timezone to be applied in order to select mails by # date. Providing none (and thus keep the default) results in errors # on some machines, so we hardcode one here. # In order to make EWS filter correctly in different timezones we need # a way to configure the enforced setting and keep the defaults if # none are given. tz = EWSTimeZone("Europe/Berlin") dt_start = EWSDateTime.from_datetime( datetime.fromtimestamp(after) if after else datetime(1990, 1, 1) ).astimezone(tz) dt_end = EWSDateTime.from_datetime( datetime.fromtimestamp(before) if before else datetime.now() ).astimezone(tz) logging.debug("fetch mails from %s (from %s)", dt_start, after) logging.debug("fetch mails to %s (from %s)", dt_end, before) return [ item.datetime_sent.timestamp() for item in self._selected_folder.filter( datetime_received__range=(dt_start, dt_end)) ]
def test_localize(self): # Test some corner cases around DST tz = EWSTimeZone('Europe/Copenhagen') with warnings.catch_warnings(): # localize() is deprecated but we still want to test it. Silence the DeprecationWarning warnings.simplefilter("ignore") self.assertEqual( str( tz.localize(EWSDateTime(2023, 10, 29, 2, 36, 0), is_dst=False)), '2023-10-29 02:36:00+01:00') self.assertEqual( str( tz.localize(EWSDateTime(2023, 10, 29, 2, 36, 0), is_dst=None)), '2023-10-29 02:36:00+02:00') self.assertEqual( str( tz.localize(EWSDateTime(2023, 10, 29, 2, 36, 0), is_dst=True)), '2023-10-29 02:36:00+02:00') self.assertEqual( str( tz.localize(EWSDateTime(2023, 3, 26, 2, 36, 0), is_dst=False)), '2023-03-26 02:36:00+01:00') self.assertEqual( str( tz.localize(EWSDateTime(2023, 3, 26, 2, 36, 0), is_dst=None)), '2023-03-26 02:36:00+01:00') self.assertEqual( str( tz.localize(EWSDateTime(2023, 3, 26, 2, 36, 0), is_dst=True)), '2023-03-26 02:36:00+02:00')
def addAgendaSubmit(self): fromDate = self.ui_addAgenda.agndFromDateInput.date() fromTime = self.ui_addAgenda.agndFromTimeInput.time() toDate = self.ui_addAgenda.agndToDateInput.date() toTime = self.ui_addAgenda.agndToTimeInput.time() fromDatetime = QDateTime(fromDate, fromTime, timeSpec=Qt.LocalTime) toDatetime = QDateTime(toDate, toTime, timeSpec=Qt.LocalTime) localTimeZone = EWSTimeZone.localzone() fromEWSDatetime = EWSDateTime.from_datetime( fromDatetime.toPyDateTime()) toEWSDatetime = EWSDateTime.from_datetime(toDatetime.toPyDateTime()) fromDT = fromEWSDatetime.astimezone(tz=localTimeZone) toDT = toEWSDatetime.astimezone(tz=localTimeZone) location = self.ui_addAgenda.agndPosInput.text() subject = self.ui_addAgenda.agndSubjectInput.text() detail = self.ui_addAgenda.agndDetailInput.toPlainText() reminderEnable = self.ui_addAgenda.agndAlarmEnableCheck.isChecked() reminder = self.ui_addAgenda.agndAlarmInput.value() self.timerRoutine.exchAccount.login() self.timerRoutine.exchAccount.addAgenda(fromDT, toDT, location, subject, detail, reminderEnable, reminder) self.addAgendaDialog.close() self.listDialog.show() self.timerRoutine.unrdAutoUpdateTimerStart() self.timerRoutine.timer2.start()
def calendarIteration(): global meetingList, busyTimes, busyTimesFlat, account, tz, year, month, day dst = time.localtime().tm_isdst calendarItems = [] now = datetime.datetime.now() day, month, year = now.day, now.month, now.year tz = EWSTimeZone.timezone('Europe/Oslo') credentials = Credentials(username=config['username'], password=config['password']) account = Account(config['account'], credentials=credentials, autodiscover=True) items = account.calendar.view( start=tz.localize(EWSDateTime(year, month, day)), end=tz.localize(EWSDateTime(year, month, day)) + datetime.timedelta(days=1), ) if dst == 0: for item in items: today_events = [item.start + datetime.timedelta(hours=1), item.end + datetime.timedelta(hours=1), item.organizer] calendarItems.append(today_events) else: for item in items: today_events = [item.start + datetime.timedelta(hours=2), item.end + datetime.timedelta(hours=2), item.organizer] calendarItems.append(today_events) meetingList = [] busyTimes = [] busyTimesFlat = [] counter = 0 for events in calendarItems: tempDict = {'start':str(calendarItems[counter][0]), 'end':str(calendarItems[counter][1]), 'title':calendarItems[counter][2].name} busyTimes = busyTimes+[list(range(int(tempDict['start'][11:16].replace(':','')),(int(tempDict['end'][11:16].replace(':','')))+1))] busyTimesFlat = [item for sublist in busyTimes for item in sublist] meetingList.append(tempDict) counter += 1 with open('web/events.json', 'w') as f: f.write(json.dumps(meetingList)) f.close()
def outlook_calendar_event_exists(appointment, calendar_service, summary): ews_tz = EWSTimeZone.timezone('America/Chicago') d = appointment.start_time.datetime start_date_time = datetime(d.year, d.month, d.day, d.hour, d.minute, d.second, d.microsecond, ews_tz) start_ews_date_time = EWSDateTime.from_datetime(start_date_time) d = appointment.end_time.datetime end_date_time = datetime(d.year, d.month, d.day, d.hour, d.minute, d.second, d.microsecond, ews_tz) end_ews_date_time = EWSDateTime.from_datetime(end_date_time) matching_events = calendar_service.calendar.find_items( start=start_ews_date_time, end=end_ews_date_time, shape=AllProperties) if matching_events: for event in matching_events: if event.subject == summary: print( "Found a matching Outlook calendar event for appointment {app}. Will not create a new one." .format(app=appointment)) return True return False
def get_email_list(self, send_time_gte, subject_like=None, sender=None): """ :param send_time_gte: must be specified :param subject_like: if None, it means no restrictions :param sender: if None, it means no restrictions :return: list type """ tz = EWSTimeZone.timezone("Asia/Shanghai") email_list = [] send_time_gte = datetime.datetime.strptime(send_time_gte, "%Y-%m-%d") inbox = self.account.inbox.filter(datetime_sent__gte=tz.localize( EWSDateTime(send_time_gte.year, send_time_gte.month, send_time_gte.day))) for item in inbox.all().order_by("-datetime_sent"): subject = item.subject if not item.sender: continue sender_name = item.sender.name send_time = ( item.datetime_sent + datetime.timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S") b1 = (True if not subject_like or subject_like.lower() in subject.lower() else False) b2 = True if not sender or sender.lower() in sender_name.lower( ) else False if b1 and b2: email_list.append([subject, sender_name, send_time]) print("get {} email(s) in total".format(len(email_list))) return email_list
def test_get_free_busy_info(self): tz = EWSTimeZone('Europe/Copenhagen') server_timezones = list(self.account.protocol.get_timezones(return_full_timezone_data=True)) start = EWSDateTime.now(tz=tz) end = EWSDateTime.now(tz=tz) + datetime.timedelta(hours=6) accounts = [(self.account, 'Organizer', False)] with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=[(123, 'XXX', 'XXX')], start=0, end=0) with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=[(self.account, 'XXX', 'XXX')], start=0, end=0) with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=[(self.account, 'Organizer', 'XXX')], start=0, end=0) with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=accounts, start=end, end=start) with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=accounts, start=start, end=end, merged_free_busy_interval='XXX') with self.assertRaises(ValueError): self.account.protocol.get_free_busy_info(accounts=accounts, start=start, end=end, requested_view='XXX') for view_info in self.account.protocol.get_free_busy_info(accounts=accounts, start=start, end=end): self.assertIsInstance(view_info, FreeBusyView) self.assertIsInstance(view_info.working_hours_timezone, TimeZone) ms_id = view_info.working_hours_timezone.to_server_timezone(server_timezones, start.year) self.assertIn(ms_id, {t[0] for t in CLDR_TO_MS_TIMEZONE_MAP.values()}) # Test account as simple email for view_info in self.account.protocol.get_free_busy_info( accounts=[(self.account.primary_smtp_address, 'Organizer', False)], start=start, end=end ): self.assertIsInstance(view_info, FreeBusyView)
def test_garbage_input(self): # Test that we can survive garbage input for common field types tz = EWSTimeZone.timezone('Europe/Copenhagen') account = namedtuple('Account', ['default_timezone'])(default_timezone=tz) payload = b'''\ <?xml version="1.0" encoding="utf-8"?> <Envelope xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Item> <t:Foo>THIS_IS_GARBAGE</t:Foo> </t:Item> </Envelope>''' elem = to_xml(payload).find('{%s}Item' % TNS) for field_cls in (Base64Field, BooleanField, IntegerField, DateField, DateTimeField, DecimalField): field = field_cls('foo', field_uri='item:Foo', is_required=True, default='DUMMY') self.assertEqual(field.from_xml(elem=elem, account=account), None) # Test MS timezones payload = b'''\ <?xml version="1.0" encoding="utf-8"?> <Envelope xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Item> <t:Foo Id="THIS_IS_GARBAGE"></t:Foo> </t:Item> </Envelope>''' elem = to_xml(payload).find('{%s}Item' % TNS) field = TimeZoneField('foo', field_uri='item:Foo', default='DUMMY') self.assertEqual(field.from_xml(elem=elem, account=account), None)
def create_meeting(self, username, start_time, end_time, subject, body, required_attendees, optional_attendees): """Create a meeting object""" account = self.connect_to_account( username, impersonation=(username != self.email)) if required_attendees: required_attendees = [ ra.strip() for ra in required_attendees.split(',') ] if optional_attendees: optional_attendees = [ oa.strip() for oa in optional_attendees.split(',') ] tz = EWSTimeZone.timezone('Etc/GMT') meeting = CalendarItem( account=account, folder=account.calendar, start=EWSDateTime.from_datetime( datetime.datetime.fromtimestamp(start_time / 1000, tz=tz)), end=EWSDateTime.from_datetime( datetime.datetime.fromtimestamp(end_time / 1000, tz=tz)), subject=subject, body=body, required_attendees=required_attendees, optional_attendees=optional_attendees) return meeting
def get_exchange_events(server: str, domain: Optional[str], username: str, password: str, range_start: datetime, range_end: datetime) -> List[CalendarEvent]: """Connect to exchange calendar server and get events within range.""" # load exchange module if necessary from exchangelib import Credentials, Configuration, Account, DELEGATE from exchangelib import EWSDateTime, EWSTimeZone # setup access full_username = r'{}\{}'.format(domain, username) if domain else username account = Account(primary_smtp_address=username, config=Configuration(server=server, credentials=Credentials( full_username, password)), autodiscover=False, access_type=DELEGATE) # collect event information within given time range events: List[CalendarEvent] = [] localzone = EWSTimeZone.localzone() local_start = localzone.localize(EWSDateTime.from_datetime(range_start)) local_end = localzone.localize(EWSDateTime.from_datetime(range_end)) for item in account.calendar.filter( ##pylint: disable=no-member start__range=(local_start, local_end)).order_by('start'): events.append( CalendarEvent(title=item.subject, start=item.start, end=item.end, duration=(item.end - item.start).seconds / 3600, categories=item.categories)) return events
def test_q(self): tz = EWSTimeZone.timezone('Europe/Copenhagen') start = tz.localize(EWSDateTime(1950, 9, 26, 8, 0, 0)) end = tz.localize(EWSDateTime(2050, 9, 26, 11, 0, 0)) result = '''\ <m:Restriction xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"> <t:And xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Or> <t:Contains ContainmentMode="Substring" ContainmentComparison="Exact"> <t:FieldURI FieldURI="item:Categories"/> <t:Constant Value="FOO"/> </t:Contains> <t:Contains ContainmentMode="Substring" ContainmentComparison="Exact"> <t:FieldURI FieldURI="item:Categories"/> <t:Constant Value="BAR"/> </t:Contains> </t:Or> <t:IsGreaterThan> <t:FieldURI FieldURI="calendar:End"/> <t:FieldURIOrConstant> <t:Constant Value="1950-09-26T08:00:00+01:00"/> </t:FieldURIOrConstant> </t:IsGreaterThan> <t:IsLessThan> <t:FieldURI FieldURI="calendar:Start"/> <t:FieldURIOrConstant> <t:Constant Value="2050-09-26T11:00:00+01:00"/> </t:FieldURIOrConstant> </t:IsLessThan> </t:And> </m:Restriction>''' q = Q(Q(categories__contains='FOO') | Q(categories__contains='BAR'), start__lt=end, end__gt=start) r = Restriction(q, folders=[Calendar()], applies_to=Restriction.ITEMS) self.assertEqual(str(r), ''.join(l.lstrip() for l in result.split('\n'))) # Test empty Q q = Q() self.assertEqual( q.to_xml(folders=[Calendar()], version=None, applies_to=Restriction.ITEMS), None) with self.assertRaises(ValueError): Restriction(q, folders=[Calendar()], applies_to=Restriction.ITEMS) # Test validation with self.assertRaises(ValueError): Q(datetime_created__range=(1, )) # Must have exactly 2 args with self.assertRaises(ValueError): Q(datetime_created__range=(1, 2, 3)) # Must have exactly 2 args with self.assertRaises(TypeError): Q(datetime_created=Build(15, 1)).clean() # Must be serializable with self.assertRaises(ValueError): Q(datetime_created=EWSDateTime(2017, 1, 1)).clean() # Must be tz-aware date with self.assertRaises(ValueError): Q(categories__contains=[[1, 2], [3, 4] ]).clean() # Must be single value
def test_ewstimezone(self): # Test autogenerated translations tz = EWSTimeZone('Europe/Copenhagen') self.assertIsInstance(tz, EWSTimeZone) self.assertEqual(tz.key, 'Europe/Copenhagen') self.assertEqual(tz.ms_id, 'Romance Standard Time') # self.assertEqual(EWSTimeZone('Europe/Copenhagen').ms_name, '') # EWS works fine without the ms_name # Test localzone() tz = EWSTimeZone.localzone() self.assertIsInstance(tz, EWSTimeZone) # Test common helpers tz = EWSTimeZone('UTC') self.assertIsInstance(tz, EWSTimeZone) self.assertEqual(tz.key, 'UTC') self.assertEqual(tz.ms_id, 'UTC') tz = EWSTimeZone('GMT') self.assertIsInstance(tz, EWSTimeZone) self.assertEqual(tz.key, 'GMT') self.assertEqual(tz.ms_id, 'UTC') # Test mapper contents. Latest map from unicode.org has 394 entries self.assertGreater(len(EWSTimeZone.IANA_TO_MS_MAP), 300) for k, v in EWSTimeZone.IANA_TO_MS_MAP.items(): self.assertIsInstance(k, str) self.assertIsInstance(v, tuple) self.assertEqual(len(v), 2) self.assertIsInstance(v[0], str) # Test timezone unknown by ZoneInfo with self.assertRaises(UnknownTimeZone) as e: EWSTimeZone('UNKNOWN') self.assertEqual(e.exception.args[0], 'No time zone found with key UNKNOWN') # Test timezone known by IANA but with no Winzone mapping with self.assertRaises(UnknownTimeZone) as e: del EWSTimeZone.IANA_TO_MS_MAP['Africa/Tripoli'] EWSTimeZone('Africa/Tripoli') self.assertEqual( e.exception.args[0], 'No Windows timezone name found for timezone "Africa/Tripoli"') # Test __eq__ with non-EWSTimeZone compare self.assertFalse(EWSTimeZone('GMT') == zoneinfo.ZoneInfo('UTC')) # Test from_ms_id() with non-standard MS ID self.assertEqual(EWSTimeZone('Europe/Copenhagen'), EWSTimeZone.from_ms_id('Europe/Copenhagen'))
def __init__(self, domain, user, password, mail_server): self.domain = domain self.user = user self.password = password self.mail_server = mail_server self.tz = EWSTimeZone.timezone('UTC') self.account = None self.history = [] self.modules = loadModules("mail_events")
def test_naive_datetime(self): # Test that we can survive naive datetimes on a datetime field tz = EWSTimeZone.timezone('Europe/Copenhagen') account = namedtuple('Account', ['default_timezone'])(default_timezone=tz) default_value = tz.localize(EWSDateTime(2017, 1, 2, 3, 4)) field = DateTimeField('foo', field_uri='item:DateTimeSent', default=default_value) # TZ-aware datetime string payload = b'''\ <?xml version="1.0" encoding="utf-8"?> <Envelope xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Item> <t:DateTimeSent>2017-06-21T18:40:02Z</t:DateTimeSent> </t:Item> </Envelope>''' elem = to_xml(payload).find('{%s}Item' % TNS) self.assertEqual(field.from_xml(elem=elem, account=account), UTC.localize(EWSDateTime(2017, 6, 21, 18, 40, 2))) # Naive datetime string is localized to tz of the account payload = b'''\ <?xml version="1.0" encoding="utf-8"?> <Envelope xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Item> <t:DateTimeSent>2017-06-21T18:40:02</t:DateTimeSent> </t:Item> </Envelope>''' elem = to_xml(payload).find('{%s}Item' % TNS) self.assertEqual(field.from_xml(elem=elem, account=account), tz.localize(EWSDateTime(2017, 6, 21, 18, 40, 2))) # Garbage string returns None payload = b'''\ <?xml version="1.0" encoding="utf-8"?> <Envelope xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Item> <t:DateTimeSent>THIS_IS_GARBAGE</t:DateTimeSent> </t:Item> </Envelope>''' elem = to_xml(payload).find('{%s}Item' % TNS) self.assertEqual(field.from_xml(elem=elem, account=account), None) # Element not found returns default value payload = b'''\ <?xml version="1.0" encoding="utf-8"?> <Envelope xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"> <t:Item> </t:Item> </Envelope>''' elem = to_xml(payload).find('{%s}Item' % TNS) self.assertEqual(field.from_xml(elem=elem, account=account), default_value)
def get_calendar_time(self, date_time): """Return a string date and time in Exchangelib format.""" # Set timezone self._tz = EWSTimeZone.timezone('Europe/Stockholm') self._calendar_time = parser.parse(date_time) return self._tz.localize( EWSDateTime(self._calendar_time.year, self._calendar_time.month, self._calendar_time.day, self._calendar_time.hour, self._calendar_time.minute))
def test_super_methods(self): tz = EWSTimeZone('Europe/Copenhagen') self.assertIsInstance(EWSDateTime.now(), EWSDateTime) self.assertIsInstance(EWSDateTime.now(tz=tz), EWSDateTime) self.assertIsInstance(EWSDateTime.utcnow(), EWSDateTime) self.assertIsInstance(EWSDateTime.fromtimestamp(123456789), EWSDateTime) self.assertIsInstance(EWSDateTime.fromtimestamp(123456789, tz=tz), EWSDateTime) self.assertIsInstance(EWSDateTime.utcfromtimestamp(123456789), EWSDateTime)
def ToEWSDateTime(_datetime): tz = EWSTimeZone.timezone('Europe/Helsinki') time = tz.localize( EWSDateTime( year=_datetime.year, month=_datetime.month, day=_datetime.day, hour=_datetime.hour, minute=_datetime.minute ) ) return time
def main(): config_file_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'exchange-calendar-to-org.cfg') config = configparser.ConfigParser() config.read(config_file_path) email = config.get('Settings', 'email') try: server_url = config.get('Settings', 'server_url') except configparser.NoOptionError: server_url = None password = config.get('Settings', 'password') sync_days = int(config.get('Settings', 'sync_days')) org_file_path = config.get('Settings', 'org_file') tz_string = config.get('Settings', 'timezone_string') sslverify = config.getboolean('Settings', 'verify_ssl') tz = EWSTimeZone.timezone(tz_string) credentials = Credentials(username=email, password=password) if server_url is None: account = Account( primary_smtp_address=email, credentials=credentials, autodiscover=True, access_type=DELEGATE) else: server = Configuration(server=server_url, credentials=credentials, verify_ssl=sslverify) account = Account( primary_smtp_address=email, config=server, autodiscover=False, access_type=DELEGATE) now = datetime.datetime.now() end = now + datetime.timedelta(days=sync_days) items = account.calendar.filter( start__lt=tz.localize(EWSDateTime(end.year, end.month, end.day)), end__gt=tz.localize(EWSDateTime(now.year, now.month, now.day)), ) text = [] text.append('* Calendar') text.append('\n') for item in items: text.append(get_item_text(item, tz)) text.append('\n') f = open(org_file_path, 'w') f.write(''.join(text))
def main(): exchAcc = ExchAccount('eas.outlook.com','******@outlook.com','********') exchAcc.login() localTimeZone = EWSTimeZone.localzone() nowDateTime = EWSDateTime.now(tz=localTimeZone) # print(EWSDateTime.now(tz=localTimeZone)) items = exchAcc.account.calendar.view(start=nowDateTime - timedelta(days=1),end=nowDateTime + timedelta(days=6)) for item in items: startTime = item.start.astimezone(tz=localTimeZone) endTime = item.end.astimezone(tz=localTimeZone) print(item.reminder_minutes_before_start)
def __init__(self, acc, pwd, ser, mail): global UTC_NOW credentials = Credentials(username=acc, password=pwd) config = Configuration(server=ser, credentials=credentials) self.my_account = Account(primary_smtp_address = mail, config=config,\ autodiscover = False, access_type = DELEGATE) tz = EWSTimeZone.timezone('UTC') self.utc_time_point = UTC_NOW print("Successfully accessed to exchange server. time:%s" % str(UTC_NOW)) print("Server:{0}, Mail:{1}, Username{2}".format(ser, mail, acc))
def send_outlook_invitation(header="Invitation", body="Please come to my meeting", attendee=None, start_time=None, end_time=None): """Sends an outlook invitation.""" logger.info("Sent outlook invitation") tz = EWSTimeZone.timezone('Europe/Stockholm') start_time = parser.parse(start_time) end_time = parser.parse(end_time) credentials = Credentials(settings.EMAIL_HOST_USER, settings.EMAIL_HOST_PASSWORD) config = Configuration(server='outlook.office365.com', credentials=credentials) account = Account(primary_smtp_address=settings.EMAIL_HOST_USER, config=config, autodiscover=False, access_type=DELEGATE) if os.environ['ENVIRONMENT_MODE'] in ['UAT', 'DEV']: header_prefix = '*** TEST SYSTEM (env {}), NO REAL DATA *** | '.\ format(os.environ['ENVIRONMENT_MODE']) else: header_prefix = '' # create a meeting request and send it out calendar_item = CalendarItem( account=account, folder=account.calendar, start=tz.localize(EWSDateTime(start_time.year, start_time.month, start_time.day, start_time.hour + 1, start_time.minute)), end=tz.localize(EWSDateTime(end_time.year, end_time.month, end_time.day, end_time.hour + 2, end_time.minute)), subject=header_prefix + header, body=body, required_attendees=[attendee] ) calendar_item.save( send_meeting_invitations=SEND_TO_ALL_AND_SAVE_COPY) logger.info("Sent calendar invitation")
def download_email(self, subject, sender, send_time): """ all three parameters must be specified only download one email each time :param subject: :param sender: :param send_time: :return: dict type """ tz = EWSTimeZone.timezone("UTC") _dict = {} send_time = datetime.datetime.strptime( send_time, "%Y-%m-%d %H:%M:%S") - datetime.timedelta(hours=8) send_time = tz.localize( EWSDateTime( send_time.year, send_time.month, send_time.day, send_time.hour, send_time.minute, send_time.second, )) inbox = (self.account.inbox.filter( datetime_sent__gte=send_time, ).filter( datetime_sent__lte=send_time).filter( subject__icontains=subject)) for item in inbox.all().order_by("-datetime_sent"): for attachment in item.attachments: if isinstance(attachment, FileAttachment): local_path = os.path.join('/Users/tongjia/Desktop/', attachment.name) with open(local_path, 'wb') as f: f.write(attachment.content) print('Saved attachment to', local_path) if sender.lower() in item.sender.name.lower(): _dict["content"] = item.text_body _dict["attachments"] = [ { "name": attachment.name, "content": attachment.content } for attachment in item.attachments if isinstance(attachment, FileAttachment) ] if _dict: print('one mail meets conditions') return _dict return
def __init__(self, sensor_service, config): super(ItemSensor, self).__init__(sensor_service=sensor_service, config=config) self._logger = self.sensor_service.get_logger(name=self.__class__.__name__) self._stop = False self._store_key = 'exchange.item_sensor_date_str' self._timezone = EWSTimeZone.timezone(config['timezone']) self._credentials = ServiceAccount( username=config['username'], password=config['password']) self.primary_smtp_address = config['primary_smtp_address'] self.sensor_folder = config['sensor_folder'] try: self.server = config['server'] self.autodiscover = False except KeyError: self.autodiscover = True
def __init__(self, username, password, server, stmp_address, tz_str='Asia/Hong_Kong'): self.username = username self.password = password self.server = server self.stmp_address = stmp_address self.url = 'https://' + server + '/EWS/Exchange.asmx' self.tz = EWSTimeZone.timezone(tz_str) self._exchangelib_connection = None self._imaplib_connection = None self._ews_connection = None
def Update(self): localTimeZone = EWSTimeZone.localzone() nowDateTime = EWSDateTime.now(tz=localTimeZone) # print(EWSDateTime.now(tz=localTimeZone)) items = self.account.calendar.view( start=nowDateTime - timedelta(days=1), end=nowDateTime + timedelta(days=6), ) retStr = [] unseenStr = [] unseenMails = self.account.inbox.filter(is_read=False) unseenStr.append(('{}'.format(unseenMails.count()))) retStr.append(unseenStr) for item in items: itemStr = [] startTime = item.start.astimezone(tz=localTimeZone) endTime = item.end.astimezone(tz=localTimeZone) dataOffset = startTime - nowDateTime dateOffNum = dataOffset.days+ dataOffset.seconds/(24.0*60.0*60.0) dateOffStr = ('%3.2f' % (dateOffNum))+'天后' if(dateOffNum>0) else ('%3.2f' % (abs(dateOffNum)))+'天前' if startTime.date()== nowDateTime.date(): dateOffStr=('今天') when = '{},{}-{}'.format(dateOffStr,startTime.strftime('%m/%d %H:%M'),endTime.strftime('%H:%M')) subject = (re.sub('(?s)([^<]*)(<.*>)(.*)', '\\1\\3', '{}'.format(item.subject))).replace('None','') detail = (re.sub('(?s)([^<]*)(<.*>)(.*)', '\\1\\3', ':{}'.format(item.body))).replace(':None','') reminderTime = startTime - timedelta(minutes=item.reminder_minutes_before_start) if(nowDateTime.strftime("%m/%d %H:%M") == reminderTime.strftime("%m/%d %H:%M")): remindNow = True else: remindNow = False reminder = ('{} min'.format(item.reminder_minutes_before_start if item.reminder_is_set else 'No remind')) location = ('@{}#{}'.format(item.location,reminder)).replace('None','') itemStr.append(when) itemStr.append('{}{}'.format(subject,detail)) itemStr.append(location) itemStr.append(remindNow) retStr.append(itemStr) return retStr
def test_localize(self): # Test some cornercases around DST tz = EWSTimeZone.timezone('Europe/Copenhagen') self.assertEqual(str(tz.localize(EWSDateTime(2023, 10, 29, 2, 36, 0))), '2023-10-29 02:36:00+01:00') with self.assertRaises(AmbiguousTimeError): tz.localize(EWSDateTime(2023, 10, 29, 2, 36, 0), is_dst=None) self.assertEqual( str(tz.localize(EWSDateTime(2023, 10, 29, 2, 36, 0), is_dst=True)), '2023-10-29 02:36:00+02:00') self.assertEqual(str(tz.localize(EWSDateTime(2023, 3, 26, 2, 36, 0))), '2023-03-26 02:36:00+01:00') with self.assertRaises(NonExistentTimeError): tz.localize(EWSDateTime(2023, 3, 26, 2, 36, 0), is_dst=None) self.assertEqual( str(tz.localize(EWSDateTime(2023, 3, 26, 2, 36, 0), is_dst=True)), '2023-03-26 02:36:00+02:00')
def delete_malicious_email(recipient_email, attachment_name): # once the recipients are found we parse their mailboxes and delete the malicious email # Args: # recipient_email (str) : malware recipient email address # attachment_name (str) : the attachment file name to identify the malicious email # Returns: # True is it parses the mailboxes, False if an error occurs # TODO: # ban the infected recipient machine with either IP or FortiClient using item.is_read account = Account(primary_smtp_address=recipient_email, config=config, autodiscover=False, access_type=IMPERSONATION) tz = EWSTimeZone.localzone() right_now = tz.localize(EWSDateTime.now()) xmin_ago = right_now - timedelta(minutes=300) try: for item in account.inbox.filter(datetime_received__gt=xmin_ago): for attachment in item.attachments: if isinstance(attachment, FileAttachment): if attachment.name == attachment_name: # Either delete the infected email, or move it to trash #item.delete() item.move_to_trash() #send an alert to the recipient m = Message( account=account, subject='FortiSIEM: You have received a Virus ' + attachment_name, body= 'The maliicous email has been deleted from your inbox, please contact your administrator for further incident response', to_recipients=[ Mailbox(email_address=recipient_email) ], ) m.send() return True except: return False
def __init__(self): # Set Timezone to local Timezone self._tz = EWSTimeZone.localzone() # set start and end time of Calendarentry self.init_time() # Logger logging.basicConfig(level=logging.WARNING, handlers=[PrettyXmlHandler()]) # Config Parser config = configparser.ConfigParser() config.read('config.txt') try: LoginData = config["Credentials"] except KeyError as error: print('The key ' + str(error) + ' were not found in the config file') exit() _Login = { "user": LoginData['user'], "password": LoginData['password'], "Primary_SMTP_Adress": LoginData['Primary SMTP Adress'] } # Credentials and account self._credentials = Credentials(username=_Login["user"], password=_Login["password"]) # Autodiscover fails w/o mail_config. See issue #337 on github exchangelib self._mailConfig = Configuration(server='outlook.office365.com', credentials=self._credentials) self._account = Account( default_timezone=self._tz, primary_smtp_address=_Login["Primary_SMTP_Adress"], config=self._mailConfig, credentials=self._credentials, autodiscover=False, access_type=DELEGATE) # Init Database self._db = exchange_database.exchange_database()
def find_malicious_email(sender_email, file_name): # identify the attributes of the email with was sent with the malicious attachment # Args: # sender_email (str) : the sender email address # file_name (str) : the attachment file name to identify the malicious email # Returns: # two lists, sibjects of the infected emails, recipients of the infected email # TODO: # Could be imroved by getting the email sent_time and use it as a filter in xmin_ago instead of the current 300 seconds recipient_emails = [] emails_subjects = [] account = Account(primary_smtp_address=sender_email, config=config, autodiscover=False, access_type=IMPERSONATION) tz = EWSTimeZone.localzone() right_now = tz.localize(EWSDateTime.now()) xmin_ago = right_now - timedelta(minutes=300) for item in account.sent.filter(datetime_sent__gt=xmin_ago): #for item in account.sent.all().order_by('-datetime_received')[:10]: for attachment in item.attachments: if isinstance(attachment, FileAttachment): if attachment.name == file_name: emails_subjects.append(item.subject) # logging.debug('Subject: '+item.subject+' '+attachment.name) if item.to_recipients is not None: for index, val in enumerate(item.to_recipients): if val.email_address not in recipient_emails: recipient_emails.append(val.email_address) if item.cc_recipients is not None: for index, val in enumerate(item.cc_recipients): if val.email_address not in recipient_emails: recipient_emails.append(val.email_address) if item.bcc_recipients is not None: for index, val in enumerate(item.bcc_recipients): if val.email_address not in recipient_emails: recipient_emails.append(val.email_address) logging.debug(emails_subjects) logging.debug(recipient_emails) return emails_subjects, recipient_emails
def handleExceptions(outlook_event, google_event): global gEvtList gEvtList = [] bIsFutureEventModified = False bIsFutureEventDeleted = False if outlook_event.modified_occurrences == None and outlook_event.deleted_occurrences == None: return if outlook_event.modified_occurrences != None: for occ in outlook_event.modified_occurrences: if isFutureDate(occ.start): bIsFutureEventModified = True if outlook_event.deleted_occurrences != None: for occ in outlook_event.deleted_occurrences: if isFutureDate(occ.start): bIsFutureEventDeleted = True # create event list in google up to if bIsFutureEventModified or bIsFutureEventDeleted: page_token = None now = datetime.now() tz = EWSTimeZone.timezone('GMT') maxDt = str( datetime(year=now.year, month=now.month, day=now.day, tzinfo=tz) + timedelta(days=max_fut_days_to_check)).replace(" ", "T") while True: gevents = google_service.events().instances( calendarId=new_cal_id, eventId=google_event['id'], pageToken=page_token, timeMax=maxDt).execute() for event in gevents['items']: if isFutureDate(event['start']['dateTime']): gEvtList.append(event) page_token = gevents.get('nextPageToken') if not page_token: break if bIsFutureEventModified: handleModifiedOccurences(outlook_event) if bIsFutureEventDeleted: handleDeletedOccurences(outlook_event)
def create_outlook_calendar_event(appointment, calendar_service, summary): ews_tz = EWSTimeZone.timezone('America/Chicago') d = appointment.start_time.datetime start_date_time = datetime(d.year, d.month, d.day, d.hour, d.minute, d.second, d.microsecond, ews_tz) start_ews_date_time = EWSDateTime.from_datetime(start_date_time) d = appointment.end_time.datetime end_date_time = datetime(d.year, d.month, d.day, d.hour, d.minute, d.second, d.microsecond, ews_tz) end_ews_date_time = EWSDateTime.from_datetime(end_date_time) event = CalendarItem( subject=summary, body='This event was created by Frontline Calendar. Contact Abby Lance with issues.', start=start_ews_date_time, end=end_ews_date_time ) calendar_service.calendar.add_items([event]) print('Outlook calendar event created. Details: {0}'.format(event))
from yaml import safe_load from exchangelib import DELEGATE, ServiceAccount, Configuration, Account, EWSDateTime, EWSTimeZone, CalendarItem logging.basicConfig(level=logging.WARNING) try: with open(os.path.join(os.path.dirname(__file__), '../settings.yml')) as f: settings = safe_load(f) except FileNotFoundError: print('Copy settings.yml.sample to settings.yml and enter values for your test server') raise categories = ['perftest'] tz = EWSTimeZone.timezone('America/New_York') verify_ssl = settings.get('verify_ssl', True) if not verify_ssl: from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter config = Configuration( server=settings['server'], credentials=ServiceAccount(settings['username'], settings['password']) ) print('Exchange server: %s' % config.protocol.server) account = Account(config=config, primary_smtp_address=settings['account'], access_type=DELEGATE) # Remove leftovers from earlier tests
from yaml import load from exchangelib import DELEGATE, services, Credentials, Configuration, Account, EWSDateTime, EWSTimeZone, CalendarItem logging.basicConfig(level=logging.WARNING) try: with open(os.path.join(os.path.dirname(__file__), 'settings.yml')) as f: settings = load(f) except FileNotFoundError: print('Copy settings.yml.sample to settings.yml and enter values for your test server') raise categories = ['perftest'] tz = EWSTimeZone.timezone('US/Pacific') config = Configuration(server=settings['server'], credentials=Credentials(settings['username'], settings['password'], is_service_account=True), verify_ssl=settings['verify_ssl']) print(('Exchange server: %s' % config.protocol.server)) account = Account(config=config, primary_smtp_address=settings['account'], access_type=DELEGATE) cal = account.calendar # Calendar item generator def calitems(): i = 0 start = tz.localize(EWSDateTime(2000, 3, 1, 8, 30, 0)) end = tz.localize(EWSDateTime(2000, 3, 1, 9, 15, 0))
#!/usr/bin/env python # https://github.com/ecederstrand/exchangelib import sys import exchangelib from exchangelib import ( Account, Configuration, Credentials, EWSDateTime, EWSTimeZone, ) from datetime import datetime, timedelta TZ = EWSTimeZone.timezone("America/New_York") class EWSAccount(object): def __init__(self, user, password): config = Configuration( server="outlook.office365.com", credentials=Credentials(username=user, password=password), ) account = Account( primary_smtp_address=user, config=config, access_type=exchangelib.DELEGATE, ) # could use this with Account(..., autodiscover=False) self.cache = { 'ews-url': account.protocol.service_endpoint,
from exchangelib import DELEGATE, Credentials, Account, EWSTimeZone, UTC_NOW import sh if '--insecure' in sys.argv: # Disable TLS when Office365 can't get their certificate act together from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter # Disable insecure TLS warnings warnings.filterwarnings("ignore") # Use notify-send for email notifications and zenity for calendar notifications notify = sh.Command('/usr/bin/notify-send') zenity = sh.Command('/usr/bin/zenity') # Get the local timezone tz = EWSTimeZone.localzone() sleep = int(sys.argv[1]) # 1st arg to this script is the number of seconds to look back in the inbox now = UTC_NOW() emails_since = now - timedelta(seconds=sleep) cal_items_before = now + timedelta(seconds=sleep * 4) # Longer notice of upcoming appointments than new emails username, _, password = netrc().authenticators('office365') c = Credentials(username, password) a = Account(primary_smtp_address=c.username, credentials=c, access_type=DELEGATE, autodiscover=True) for msg in a.calendar.view(start=now, end=cal_items_before)\ .only('start', 'end', 'subject', 'location')\ .order_by('start', 'end'): if msg.start < now: continue minutes_to_appointment = int((msg.start - now).total_seconds() / 60)
def connect(): credentials = ServiceAccount(username=userconfig['ews']['username'], password=userconfig['ews']['password']) ews_config = Configuration(server=userconfig['ews']['server'], credentials=credentials) account = Account( config=ews_config, primary_smtp_address=userconfig['ews']['primary_smtp_address'], autodiscover=False, access_type=DELEGATE ) return account if __name__ == '__main__': account = connect() tz = EWSTimeZone.timezone('Europe/Berlin') d = datetime.today() year, month, day = (d.year, d.month, d.day) items = account.calendar.view( start = tz.localize(EWSDateTime(year, month, day)), end = tz.localize(EWSDateTime(year, month, day + 5)) #, #categories__contains=['foo', 'bar'], ) #qs = account.calendar.all() #qs.filter(start__range=(dt1, dt2)) # Returns items starting within range. Only for date and numerical types kal = LocalCalendar()