ActiveSync

Exchange ActiveSync (EAS) is a protocol for synchronizing email, contacts, calendar, tasks, and notes between mobile clients and a groupware server. EAS uses WAP Binary XML (WBXML) over HTTP/HTTPS. It was originally developed by Microsoft for Exchange, but is now supported by iOS Mail, Android, Outlook 2013+, Windows Mail, and many third-party clients.

In addition to synchronization, the protocol provides device management and security features (provisioning, remote wipe, PIN policies).

People

Michael Rubinsky
Torben Dannhauer

Bugs

See the bug tracker, the list of known issues, and broken client behavior.

Description

The Horde_ActiveSync library provides the protocol engine for synchronizing a Horde groupware stack with EAS clients. In a typical Horde 6 deployment the data backend is Horde_Core_ActiveSync_Driver in horde/core, which talks to IMP (mail), Kronolith (calendar), Turba (contacts), Nag (tasks), and Mnemo (notes).

For the feature matrix by EAS version, see ActiveSync Feature Grid. For developer-oriented protocol documentation, see the horde/activesync README and the API documentation.

Horde 6 ActiveSync passes Microsoft's Remote Connectivity Analyzer when provisioning is disabled for the test account (the analyzer does not respond to the HTTP 449 header sent when provisioning is required).

Server Setup

Enable ActiveSync in Horde

Activate ActiveSync in Horde administration -> ActiveSync tab (or var/config/horde/conf.php). Create the SQL state tables from the Horde configuration screen when prompted.

Minimum configuration:

$conf['activesync']['enabled'] = true;
$conf['activesync']['version'] = '16.1';   // global EAS ceiling
$conf['activesync']['storage'] = 'Sql';
$conf['activesync']['emailsync'] = true;
$conf['activesync']['auth']['type'] = 'basic';

History ($conf['history']['enabled']) must be enabled -- ActiveSync relies on it for change tracking.

Web server

Clients expect two URL paths to reach Horde's RPC endpoint:

In a Composer-based Horde 6 deployment, the web-readable entry point is web/horde/rpc.php (symlinked from the package tree). Your web server document root should point at the deployment's web/ directory.

Apache

Recommended rewrite rules (case-insensitive Autodiscover, v1 and v2):

<IfModule mod_rewrite.c>
    RewriteEngine On

    # Pass MS headers through mod_proxy_fcgi to PHP-FPM when needed:
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    RewriteRule .* - [E=HTTP_MS_ASPROTOCOLVERSION:%{HTTP:Ms-Asprotocolversion}]
    RewriteRule .* - [E=HTTP_X_MS_POLICYKEY:%{HTTP:X-Ms-Policykey}]

    # Autodiscover v1 (POX/XML) -- [NC] is required; iOS sends /Autodiscover/Autodiscover.xml
    RewriteRule "^/autodiscover/autodiscover\.xml$" "/horde/rpc.php" [NC,L]

    # Autodiscover v2 (JSON) -- no $ anchor; path continues with /v1.0/<email>
    RewriteRule "^/autodiscover/autodiscover\.json" "/horde/rpc.php" [NC,L,QSA]

    # ActiveSync
    RewriteRule "^/Microsoft-Server-ActiveSync" "/horde/rpc.php" [L,QSA]
</IfModule>

Note: An Alias to rpc.php also works when PHP runs as mod_php in the same vhost. With mod_proxy_fcgi, prefer RewriteRule as shown. If Authorization headers are not passed to PHP, the E=HTTP_AUTHORIZATION rule above usually fixes it.

Note: Horde 6 uses symlinks under web/ into vendor/. Make sure rewrites target /horde/rpc.php relative to the vhost document root that serves Horde.

nginx

location /Microsoft-Server-ActiveSync {
    rewrite ^ /horde/rpc.php last;
}
location ~* ^/autodiscover/autodiscover\.xml$ {
    rewrite ^ /horde/rpc.php last;
}
location ~* ^/autodiscover/autodiscover\.json {
    rewrite ^ /horde/rpc.php last;
}

Pass Authorization, Ms-Asprotocolversion, and X-Ms-Policykey headers to PHP-FPM. Increase fastcgi_read_timeout (or equivalent) for long-poll Ping requests -- see Reverse proxy below.

lighttpd

alias.url = (
    "/Microsoft-Server-ActiveSync" => "/var/www/horde/web/horde/rpc.php",
    "/autodiscover/autodiscover.xml" => "/var/www/horde/web/horde/rpc.php",
    "/autodiscover/autodiscover.json" => "/var/www/horde/web/horde/rpc.php"
)

Use case-insensitive matching or multiple alias entries if your clients vary path casing.

Autodiscover

Autodiscover tells the device where the ActiveSync server lives. Horde supports both Autodiscover protocols:

Protocol Request Auth Response
v2 JSON GET /autodiscover/autodiscover.json/v1.0/<email>?Protocol=ActiveSync None {"Protocol":"ActiveSync","Url":"https://.../Microsoft-Server-ActiveSync"}
v1 POX/XML POST /autodiscover/autodiscover.xml HTTP Basic XML with ActiveSync and optional IMAP/SMTP settings

Modern clients (recent iOS, Outlook) try v2 first, then fall back to v1. Both must reach rpc.php via the web server rules above. A v2 404 alone is harmless (clients fall back), but routing v2 is recommended for faster account setup.

SSL is required for production Autodiscover. Self-signed certificates require the device to trust the CA.

Email domain vs Horde hostname

Autodiscover is driven by the email domain -- the part after @. For user@example.com, the device queries example.com and autodiscover.example.com. It does not know that Horde might live on mail.example.com or webmail.example.com unless discovery succeeds and returns that URL.

This matters when Horde runs on a different host than the email domain (very common).

Discovery sequence

For user@example.com, a typical iOS/Outlook client tries, in order:

  1. GET https://example.com/autodiscover/autodiscover.json/v1.0/user@example.com?Protocol=ActiveSync (v2)
  2. POST https://example.com/autodiscover/autodiscover.xml (v1)
  3. POST https://autodiscover.example.com/autodiscover/autodiscover.xml (v1)
  4. GET http://autodiscover.example.com/autodiscover/autodiscover.xml -- expects a 302 redirect to HTTPS, then POST
  5. DNS SRV lookup _autodiscover._tcp.example.com -> POST to the target host

DNS is used in two ways: A/AAAA records for each hostname in steps 1-4, and an optional SRV record in step 5:

_autodiscover._tcp.example.com.  3600  IN  SRV  0 1 443 mail.example.com.

Point the SRV target at the host that actually serves Horde Autodiscover.

Path case sensitivity

Microsoft documentation uses mixed case (AutoDiscover/AutoDiscover.xml). Real clients often send /Autodiscover/Autodiscover.xml or /autodiscover/autodiscover.xml -- the difference is the d in the middle of the word. Apache RewriteRule is case-sensitive unless [NC] is set. Use [NC] on all Autodiscover rewrite rules.

Single-host setup

When Horde and the email domain are the same host (e.g. https://example.com/horde for user@example.com), the Apache/nginx rules in Web server above are sufficient. No redirect is needed.

Multi-host / central Horde setup

When email addresses use @example.com but Horde runs on https://mail.example.com, configure each email-domain vhost to forward Autodiscover to the Horde host.

On the email-domain vhost (e.g. example.com, autodiscover.example.com) -- not the Horde host:

RedirectMatch 302 (?i)/autodiscover/autodiscover.xml https://mail.example.com/autodiscover/autodiscover.xml
RedirectMatch 302 (?i)^(/autodiscover/autodiscover\.json.*)$ https://mail.example.com$1

Autodiscover clients follow the redirect and re-send the request. If a client drops the POST body on 302, use Redirect 307 instead.

Port 80 redirect for step 4 above:

<VirtualHost *:80>
    ServerName autodiscover.example.com
    RedirectMatch 302 (?i)/autodiscover/autodiscover.xml https://mail.example.com/autodiscover/autodiscover.xml
</VirtualHost>

Important: Do not install ActiveSync rewrite rules on vhosts that are not the Horde document root. If a non-Horde vhost rewrites Autodiscover to /horde/rpc.php but has no horde/ directory, requests return 404 and any RedirectMatch on the same vhost will not run (mod_rewrite is evaluated before mod_alias). Email-domain vhosts should only redirect to the Horde host; the Horde host vhost carries the rpc.php rewrites.

Horde Autodiscover configuration

Horde must map the email address from the Autodiscover request to a Horde username. Configure this on the ActiveSync tab (autodiscovery settings). Hooks are available for custom logic -- see horde/config/hooks.php.dist (activesync_get_autodiscover_username, activesync_autodiscover_xml, activesync_autodiscover_parameters).

If Autodiscover authentication fails, the device falls back to manual setup.

Verifying Autodiscover

Test Expected result
POST https://mail.example.com/autodiscover/autodiscover.xml (no credentials) 401 -- Horde asks for auth; routing works
Same request 404 -- routing broken (check rewrite rules and vhost)
GET .../autodiscover.json/v1.0/user@example.com?Protocol=ActiveSync **200** JSON with ActiveSync URL (if v2 routed)
Valid credentials on v1 POST **200** XML with server URLs

Example:

curl -ks -o /dev/null -w "%{http_code}\n" \
  -X POST -H "Content-Type: text/xml" --data "<x/>" \
  https://mail.example.com/autodiscover/autodiscover.xml

A 401 response with realm "Horde ActiveSync" means the request reached rpc.php correctly.

Reverse proxy

ActiveSync Ping holds connections open for up to 3540 seconds (depending on client and $conf['activesync']['ping']['heartbeatmax']). Reverse proxies must not time out sooner.

Apache backend example:

ProxyPass        / https://192.168.1.230/ connectiontimeout=600 timeout=4000
ProxyPassReverse / https://192.168.1.230/
ProxyTimeout 5400

Adjust timeouts for your environment. Similar proxy_read_timeout / fastcgi_read_timeout settings apply for nginx.

PHP execution time

Set max_execution_time to 0 or at least twice the maximum heartbeat interval. Configure this in Horde's general configuration tab or in php.ini / the PHP-FPM pool.

Administration

Administrators manage ActiveSync under Horde administration -> ActiveSync and ActiveSync Devices.

Key options on the ActiveSync tab:

Setting Purpose
Enable ActiveSync Master switch
Storage backend Sql or Nosql (MongoDB) for device state
Highest EAS version Global protocol ceiling (2.5 ... 16.1)
Email sync Enable/disable mail collections
Autodiscovery Username mapping from email address
Logging Path, level, per-device log files
Ping heartbeat min/max Long-poll interval bounds

Per-user EAS version limits are set under Permissions -> ActiveSync -> Maximum ActiveSync protocol version -- not in user preferences. Per-device limits use the activesync_device_version hook with version_mode = device in conf.php.

Provisioning mode: None, Allow, or Force -- see Provisioning/Remote Wipe below.

Device management: administrators can view all paired devices, request remote wipe, force re-provisioning, and block devices. Per-device protocol log files are supported (logging.type = perdevice); a per-device log toggle in the admin GUI is still on the roadmap.

Microsoft documentation on EAS security policies.

Application Configuration

No additional steps are normally required for synchronization of the supported applications. Each application has user preferences for which shares are synchronized. For example, in Kronolith the user's default calendar is always synchronized; additional owned calendars can be selected.

Multiple sources in the same collection

Starting with Horde 5.2, applications can expose discrete calendars, address books, task lists, and note pads on the client instead of multiplexing them into a single collection. Not all EAS clients support this.

All sync-able sources must be writable by the user.

Users manage paired devices under Global Preferences -> ActiveSync Devices (force re-sync, remote wipe).

Email Support

Email synchronization can be disabled on the ActiveSync tab. ActiveSync email requires IMAP; POP3 is not supported. In the Horde stack, IMP's configured IMAP server is used.

QRESYNC and per-mailbox MODSEQ on the IMAP server greatly improve performance. An IMAP proxy can also help.

Supported mail flags: seen and flagged for follow up. Flag-only changes trigger a sync when MODSEQ is available; otherwise a new message arrival triggers sync and flag changes are picked up in the same pass.

ActiveSync does not support the IMAP \Deleted flag. Messages flagged deleted in a desktop MUA are not removed on the device until expunged. Configure a Trash folder in IMP for device-side deletes to move messages instead of immediate expunge.

S/MIME Support

S/MIME signing and encryption work when IMP S/MIME is configured. Native iOS and Outlook clients generally support S/MIME over ActiveSync. Most Android native mail clients do not support S/MIME; third-party clients may.

ActiveSync Versions

Horde 6 supports EAS 2.5 through 16.1. See Supported ActiveSync Features for the full matrix.

Notable version milestones:

EAS version Exchange equivalent Highlights
12.0 / 12.1 2007 HTML mail, follow-up flags, WBXML provisioning
14.0 / 14.1 2010 Outlook 2013+ sync, extended search
16.0 2016 Calendar instance model, draft sync, mailbox Find/KQL
16.1 2016+ Propose-new-time (COUNTER), account-only remote wipe

Version negotiation: the server advertises a ceiling (conf['activesync']['version']); the client sends MS-ASProtocolVersion per request. Per-user permissions and per-device hooks can lower (or in some cases raise) the ceiling for individual accounts or devices.

Provisioning / Remote Wipe

Provisioning registers devices with the server and enables policy enforcement (PIN, complexity, failed-attempt limits) and remote wipe.

Enable provisioning via the permissions tree: Horde -> ActiveSync -> Provisioning -> individual policies.

Mode Behavior
None No provisioning; remote wipe disabled
Allow Provision devices that support it; others may still connect
Force Only provisioned devices may connect

EAS 16.1 adds account-only remote wipe for devices negotiating >= 16.1.

Users and administrators initiate wipe from the device management UI. The wipe command is sent on the device's next non-PING request. Status Pending can be cancelled; status Wiped requires removing the device entry before it can pair again.

Client Compatibility

Contacts, calendar, tasks, notes, and email all sync through Horde ActiveSync. Current iOS Mail, Android (Gmail, Samsung), Outlook 2013+, and Windows Mail generally work with EAS 14.1+. EAS 16.x features require clients and server configuration that negotiate 16.0 or 16.1.

Not all devices support tasks or notes natively. Check known issues and broken client behavior before troubleshooting a specific client.

For the complete feature set by protocol version, see Supported ActiveSync Features.

Setting up the device

Create a new account of type Microsoft Exchange, Exchange, or Corporate. Enter the Horde username and password.

With Autodiscover configured, enter only the email address and password -- the device discovers the server. Without Autodiscover, set the server to the hostname of the vhost that serves Horde (e.g. mail.example.com), not the full URL path. The ActiveSync path /Microsoft-Server-ActiveSync is implied.

SSL should be enabled for production. Self-signed certificates must be trusted on the device.

After setup, select which folders/collections to synchronize. Some clients require a manual folder refresh after the initial sync.

Outlook Connectivity

Outlook 2013 and later can sync via ActiveSync (requires EAS >= 14.0). ActiveSync does not provide full Exchange functionality in Outlook.

With Autodiscover working, use the standard email account wizard. For manual setup, choose Outlook.com or Exchange ActiveSync compatible service -- not Microsoft Exchange Server or compatible service.

Outlook does not use EAS for Free/Busy lookup. Provide Kronolith's Free/Busy URL under File -> Options -> Calendar -> Free/Busy Options:

https://example.com/horde/kronolith/fb.php?u=%NAME%

%NAME% is replaced with the mailbox user portion of the meeting address.

Troubleshooting

First, check known issues and the bug tracker.

Autodiscover fails / account setup loops:

Setup succeeds but no data appears:

Collecting diagnostics:

tshark capture

For unencrypted HTTP debugging:

tshark 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' -w /path/to/capture.pcap

SSL capture requires the server's RSA private key and non-forward-secret ciphers -- use only on test systems.

Roadmap

Historical milestones and current Horde 6 work. For protocol-level detail on EAS 16, see the horde/activesync README. Open library refactor items are tracked in the package doc/todo.md.

Horde 5.1

Feature Status
EAS 14(.1) support. Complete.
Improved device management via hooks. Complete.
Support for SOFTDELETE. Complete.

Horde 5.2

Feature Status
Improved email identity support. Complete.
Support for multiple sources per collection. E.g., multiple calendars, addressbooks etc... Complete.
Improved device management GUI. Complete.

Horde 6.0

Protocol and core stack

Feature Status
EAS 16.0 support in applications. Complete (calendar instance model, draft sync, Find/KQL, ClientUid, Location, SmartForward Forwardee).
EAS 16.1 support. Complete (propose-new-time / METHOD=COUNTER, DisallowNewTimeProposal, account-only remote wipe).
Per-user EAS version ceiling via permissions. Complete (horde:activesync:version).
Per-device EAS version ceiling via hook. Complete (activesync_device_version with version_mode = device).
EAS 16.0 Find command (mailbox/GAL search). Complete -- KQL parser in horde/activesync, IMP search backend in horde/core.
Autodiscover v2 JSON (autodiscover.json). Complete in PHP; requires web server routing (see Autodiscover above).
Autodiscover v2 JSON response hardening. Complete (Protocol default, json_encode).
Multiplexed PIM folders (multiple calendars, address books, task lists, note pads). Complete.

Calendar, mail, and invitations (2026)

Feature Status
EAS 16.0 recurring calendar instance sync. Complete -- bound/modified instances, exception deletion (horde/kronolith).
Meeting invitations in mail (recurring RRULE / RECURRENCE-ID in MeetingRequest). Complete.
MeetingResponse RSVP and propose-new-time from device. Complete -- includes InstanceId -> RECURRENCE-ID mapping.
IMP iTip RSVP UI above invitation mail body. Complete.
EAS 16.0 draft mail sync (create/edit/send drafts on device). Complete.
FILTERTYPE_INCOMPLETETASKS for task collections. Complete (horde/core / horde/nag).

Stability and client compatibility (2026)

Feature Status
SQL/Mongo row locks for parallel device state access. Complete.
Reject and repair corrupt collection sync_data. Complete.
Separate PING watermark from SYNC modseq (iOS mail loop fix). Complete.
FOLDERSYNC_REQUIRED loop guard for broken clients. Complete.
Modern iOS Notes multiplexing behaviour. Complete.
PING orphan-collection and hierarchy-sync recovery. Complete.
ItemOperations fetch fixes (deleted messages, folder type). Complete.

Administration and operations

Feature Status
Improved device management GUI (grouped by user, collection details, account wipe). Complete.
Per-device protocol log files (logging.type = perdevice). Complete.
Ability for admin to toggle sync log on/off per device from GUI and view via GUI. Planned.
CLI admin tool. If sponsored.
EAS usage dashboard / live operator monitor. Planned (separate admin tool; not in protocol library).

Still open or deferred

Feature Status
SMS synchronization. Planned -- today SMS collections are stubbed so broken clients do not break mail sync; full backend support targeted for Horde 6 refactor.
ItemOperations:Schema requests. Deferred -- no known client requires this.
HTTP 503 throttling (X-MS-Throttle). Deferred -- relevant only at high load.
Task Regenerate=1 (Outlook post-completion regeneration). Not supported -- Nag uses completions[], not regenerated due dates.
Horde 6 library refactor (PSR-4 class names, horde/http request/response, pluggable driver subsystems, storage layer rename). Planned -- breaking changes; see horde/activesync doc/todo.md.

EAS 16.0/16.1 application support shipped in the Horde 6 / ActiveSync 3.x line on FRAMEWORK_6_0. See Supported ActiveSync Features for the version matrix.

Horde_ActiveSync vs. Z-Push

Horde_ActiveSync protocol handling was originally based on Z-Push but has been heavily refactored. Key advantages of Horde's stack:

  1. Modularity -- pluggable Horde_ActiveSync_Driver_Base backends; state and diff logic are separate.
  2. Efficiency -- Horde History-based change tracking instead of Z-Push file-based UID polling.
  3. Integrated groupware -- calendar recurrence, timezone handling, and appointment logic built in.
  4. IMAP -- uses Horde_Imap_Client with QRESYNC instead of the PHP c-client extension.
  5. Configuration -- heartbeat, security policies, and provisioning via Horde admin UI and permissions.
  6. Protocol coverage -- EAS 16.0/16.1 in Horde 6 vs Z-Push's more limited Exchange-version support.

Resources

Protocol documentation

Horde wiki

Other implementations