Skip to main content

EWS Contact Synchronization

Auto-generated

This page is imported automatically from an external repository.

Source project: Open repository

This module provides the functionality to synchronize ADITO contacts (persons & organisations) into a Microsoft Exchange mailbox via Exchange Web Services (EWS).

Users can save searches (filters) in the client and share them for synchronization to Outlook. Two server processes then take care of maintaining a sync table and of the actual transfer to Exchange.

What gets synchronized

Information transferred from ADITO to Exchange per contact:

  • Salutation, first name, last name
  • Department, role/job title, position
  • Organisation (company name)
  • Address (business address)
  • Communication data: phone (business/mobile/fax/…), email, homepage
  • Category Adito_CRM (used to distinguish these contacts from ones manually created in Outlook)
info

In its standard variant, the sync is one-way — from ADITO to Exchange only. Changes made directly in Outlook/Exchange are not written back to ADITO and will be overwritten on the next sync when the ADITO record changes.

Requirements

Peer dependencies

See package.json

Exchange alias & impersonation

An Exchange alias with a valid configuration must exist in the project. By default the module uses the alias set in the instance config key calendarAlias (fallback: "Exchange").

Database

The module ships its own alias EwsSync_Data_alias, mapped onto Data_alias. It contains the following tables (created via Liquibase in .liquibase/EwsSync_Data_alias/):

TablePurpose
AB_SYNCCONTACTSync state table: which contact belongs to which user, together with its EXCHANGEID, UPDATECONTACT flag, DATE_DEL for pending deletions
EWS_INFO_LOGLog table for all activities of both processes (results, errors, info messages with a priority)
SEARCHFILTERSaved searches that the user has shared in the client — the basis for selecting which contacts to sync
note

On PostgreSQL, the extension uuid-ossp is required because EwsClientSyncUtils.updateEntrysInSyncTable() internally uses maskingUtils.newUUID().

Configuration

Preferences (PREFERENCES_PROJECT → custom preferences)

KeyDescriptionDefault
custom.ews.activeMaster switch. The processes only run when this is true.false
custom.ews.syncsizeMaximum number of contacts per filter/user per sync run (protects Outlook profiles from being flooded).7200
tip

Both server processes log an info entry EWS is disabled. Enable it in PREFERENCES_PROJECT as long as custom.ews.active is not set. This is a common first stumbling block during setup.

Instance config

KeyDescriptionDefault
calendarAliasName of the Exchange alias used for synchronization.Exchange

User configuration

For every user whose contacts should be synced, the mailbox (CALENDARID) must be maintained in the user attributes. Without a mailbox, the user is skipped and an entry "No Exchange-Configuration found for User" is written to EWS_INFO_LOG.

Architecture

The module consists of two server processes, an audit-service hook, and the corresponding libraries and entities.

┌───────────────────────────────┐ ┌────────────────────────────────┐
│ Client │ │ process_audit_service │
│ SyncedSearches_entity │ │ → EwsSyncAudit_lib │
│ SearchSync_entity │ │ (marks AB_SYNCCONTACT │
│ → share filter for sync │ │ rows as "changed") │
└───────────────┬───────────────┘ └─────────────┬──────────────────┘
│ │
▼ ▼
┌────────────────────────────────────────────────────┐
│ EwsSyncContact_serverProcess (sync table) │
│ evaluates filters, maintains AB_SYNCCONTACT │
│ (insert / update-flag / soft-delete via DATE_DEL) │
└────────────────────────────┬───────────────────────┘


┌────────────────────────────────────────────────────┐
│ EwsSyncToExchange_serverProcess (Exchange sync) │
│ → EwsClient_lib (EwsSyncContactUtils) │
│ → @aditosoftware/ews (EwsClientPlugin) │
│ transfers changes to the mailbox │
└────────────────────────────┬───────────────────────┘

Exchange / Outlook

Server processes (process/)

EwsSyncContact_serverProcess

Prepares the synchronization. On each run, for every user, it evaluates the user's shared search filters (db.toFilterCondition) and maintains the AB_SYNCCONTACT table:

  • Insert new hits of a filter
  • Flag (UPDATECONTACT = 1) contacts that were changed in ADITO but had already been synced
  • Soft-delete via DATE_DEL for contacts that no longer match the filter
note

For db.toFilterCondition to work in the background, the process must be configured in the Manager with timer type TIMERTYPE_SERVER and a specific user attached.

EwsSyncToExchange_serverProcess

Sends the prepared changes from AB_SYNCCONTACT to Exchange. It iterates over all syncing users (getAllExchangeUser) and, in this order, calls:

  1. EWSdeleteContactsForUser – deletes contacts with DATE_DEL set from Exchange and removes the row from AB_SYNCCONTACT.
  2. EWSupdateContactsForUser – pushes all rows with UPDATECONTACT = 1.
  3. EWSinsertContactsForUser – creates new contacts. The unique id returned by Exchange is stored in EXCHANGEID.

By default, contacts are written to the mailbox's default contact folder and tagged with the category Adito_CRM.

warning

The Exchange id (EXCHANGEID) is case-sensitive: Bx234967Elbn ≠ BX234967ELBN.

warning

Contacts are pushed to Exchange in blocks of 200. If the server restarts while a batch is in flight, contacts may end up duplicated in Outlook (because the returned EXCHANGEID was never persisted). Disable the process before planned restarts.

migrateToEwsSearchFilter_serverProcess

One-time migration of legacy EWS sync configuration from ASYS_USERS (PROPKEY SearchSync) into the new SEARCHFILTER table. Only relevant for projects coming from the previous sync implementation.

Libraries (process/)

LibraryContents
EwsClient_libLow-level wrapper around the EwsClientPlugin: EwsSyncContactUtils.insertContactsToFolder, .updateContacts, .deleteContactByID, .getContactFolders, plus EwsSyncContactXMLUtils for XML mapping.
EwsSyncContact_libHigh-level logic in EwsClientSyncUtils: maintains the sync table, resolves filters into contact sets, hands contact data to EwsClient_lib, writes log entries.
EwsSyncAudit_libInvoked by the process_audit_service (see below). Sets UPDATECONTACT = 1 / DATE_DEL when relevant fields change.

All three libraries are override-capable via LibraryOverrideManager_lib — projects can replace individual functions without forking the module.

Audit configuration

By default, EwsSyncAudit_lib reacts to the following columns:

"CONTACT": ["DEPARTMENT", "CONTACTROLE", "CONTACTPOSITION", "ADDRESS_ID"],
"ORGANISATION": ["NAME"],
"ADDRESS": ["ZIP", "ADDRESS", "BUILDINGNO", "COUNTRY", "CITY", "PROVINCE", "ADDR_TYPE"],
"PERSON": ["FIRSTNAME", "LASTNAME"],
"COMMUNICATION": ["ADDR", "MEDIUM_ID", "ISSTANDARD"]

If e.g. CONTACT.DEPARTMENT changes → the update flag is set. If CONTACT.STATUS changes → nothing happens (not on the whitelist).

Entities (entity/)

EntityPurpose
SyncedSearches_entityOverview of a user's shared searches, manual re-sync, filter export
SearchSync_entityManages the individual sync entries per search
Synccontact_entityRead-only view onto AB_SYNCCONTACT
EwsSyncAddContacts_entityClient action to manually add contacts to the sync

Based on practical experience very good experiences were made with the following intervals:

ProcessInterval
EwsSyncContact_serverProcess (maintain sync table)45 min
EwsSyncToExchange_serverProcess (push to Exchange)30 min

Debugging

  • Process history in the Manager — every run writes its errors and results there.
  • Table EWS_INFO_LOG — every relevant activity is logged with USER_ID, TYPE, PRIORITY (LOW / MEDIUM / HIGH) and detail INFO.
  • Debug mode — set doDebug = true at the top of either server process to get additional per-user and per-contact logs.

Typical Exchange error:

"The server cannot service this request right now. Try again later"

Happens when too many contacts are pushed in a short time. Not fatal — the next run resends the batch until everything is transferred.

Important notes / caveats

  • The sync is one-way (see above). Changes made in Outlook are overwritten.
  • The Exchange id is case-sensitive.
  • Disable EwsSyncToExchange_serverProcess before planned server restarts to avoid duplicates.
  • Without an impersonation user configured in the Exchange alias, every sync fails.
  • PostgreSQL requires the uuid-ossp extension.

Deprecated / removed

The following parts of the old EWS sync implementation were removed in 4.0.0 (see CHANGELOG.md):

  • ewsSyncContacts_serverProcess → replaced by EwsSyncContact_serverProcess
  • EwsClientSync_lib → replaced by EwsSyncContact_lib
  • Actions addToContactSync / removeFromContactSync on the Person_entity