EWS Contact Synchronization
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)
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/):
| Table | Purpose |
|---|---|
AB_SYNCCONTACT | Sync state table: which contact belongs to which user, together with its EXCHANGEID, UPDATECONTACT flag, DATE_DEL for pending deletions |
EWS_INFO_LOG | Log table for all activities of both processes (results, errors, info messages with a priority) |
SEARCHFILTER | Saved searches that the user has shared in the client — the basis for selecting which contacts to sync |
On PostgreSQL, the extension uuid-ossp is required because EwsClientSyncUtils.updateEntrysInSyncTable() internally uses maskingUtils.newUUID().
Configuration
Preferences (PREFERENCES_PROJECT → custom preferences)
| Key | Description | Default |
|---|---|---|
custom.ews.active | Master switch. The processes only run when this is true. | false |
custom.ews.syncsize | Maximum number of contacts per filter/user per sync run (protects Outlook profiles from being flooded). | 7200 |
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
| Key | Description | Default |
|---|---|---|
calendarAlias | Name 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_DELfor contacts that no longer match the filter
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:
EWSdeleteContactsForUser– deletes contacts withDATE_DELset from Exchange and removes the row fromAB_SYNCCONTACT.EWSupdateContactsForUser– pushes all rows withUPDATECONTACT = 1.EWSinsertContactsForUser– creates new contacts. The unique id returned by Exchange is stored inEXCHANGEID.
By default, contacts are written to the mailbox's default contact folder and tagged with the category Adito_CRM.
The Exchange id (EXCHANGEID) is case-sensitive: Bx234967Elbn ≠ BX234967ELBN.
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/)
| Library | Contents |
|---|---|
EwsClient_lib | Low-level wrapper around the EwsClientPlugin: EwsSyncContactUtils.insertContactsToFolder, .updateContacts, .deleteContactByID, .getContactFolders, plus EwsSyncContactXMLUtils for XML mapping. |
EwsSyncContact_lib | High-level logic in EwsClientSyncUtils: maintains the sync table, resolves filters into contact sets, hands contact data to EwsClient_lib, writes log entries. |
EwsSyncAudit_lib | Invoked 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/)
| Entity | Purpose |
|---|---|
SyncedSearches_entity | Overview of a user's shared searches, manual re-sync, filter export |
SearchSync_entity | Manages the individual sync entries per search |
Synccontact_entity | Read-only view onto AB_SYNCCONTACT |
EwsSyncAddContacts_entity | Client action to manually add contacts to the sync |
Recommended process intervals
Based on practical experience very good experiences were made with the following intervals:
| Process | Interval |
|---|---|
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 withUSER_ID,TYPE,PRIORITY(LOW/MEDIUM/HIGH) and detailINFO. - Debug mode — set
doDebug = trueat 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_serverProcessbefore planned server restarts to avoid duplicates. - Without an impersonation user configured in the Exchange alias, every sync fails.
- PostgreSQL requires the
uuid-osspextension.
Deprecated / removed
The following parts of the old EWS sync implementation were removed in 4.0.0 (see CHANGELOG.md):
ewsSyncContacts_serverProcess→ replaced byEwsSyncContact_serverProcessEwsClientSync_lib→ replaced byEwsSyncContact_lib- Actions
addToContactSync/removeFromContactSyncon thePerson_entity