CRM Integration Guide
How to connect EmailEngine to a CRM: syncing mail into contact records, tracking activity, and sending from the user's own mailbox.
Overview
EmailEngine is frequently utilized by smaller, niche CRM systems for email integration, such as those designed for managing donations at a church or coordinating influencers for marketing campaigns.
When integrating email with a CRM system, it typically involves connecting the CRM users' email accounts to the platform. This integration provides two key benefits:
- Outbound: Users can send emails directly from the CRM to their contacts while maintaining their personal identity
- Inbound: The CRM actively monitors connected email accounts, identifying and tracking email exchanges with CRM contacts
Architecture Overview
Data Flow
- User Authentication: CRM user connects their email account via EmailEngine
- Initial Sync: EmailEngine performs initial mailbox synchronization
- Webhook Notifications: EmailEngine sends webhooks for new incoming and sent emails
- Contact Matching: CRM matches email addresses with contacts
- Activity Logging: Email interactions are logged as CRM activities
- Outbound Sending: CRM users send emails through EmailEngine's API
Connecting Email Accounts
Using the Authentication Form
Instead of requesting credentials through your CRM UI, use EmailEngine's built-in authentication form feature. This approach is more convenient and secure:
curl -XPOST \
"https://emailengine.example.com/v1/authentication/form" \
-H "Authorization: Bearer <TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"account": "USER_ID",
"name": "User Name",
"email": "user@example.com",
"subconnections": [
"\\Sent"
],
"redirectUrl": "https://myapp/account/settings.php"
}'
Parameters:
| Parameter | Description |
|---|---|
account | User ID from your CRM system (for consistency) |
name | User's display name |
email | User's email address |
subconnections | Additional folders for instant notifications (see below) |
redirectUrl | URL to redirect user after authentication |
Response:
{
"url": "https://emailengine.example.com/accounts/new?data=eyJhY2NvdW50Ijo..."
}
Redirect the user's browser to this URL to initiate authentication.
Benefits of Authentication Form
- No Password Handling: Your application never handles passwords or OAuth tokens
- OAuth2 Support: Users can authenticate via OAuth2 providers (Gmail, Outlook, etc.)
- Secure Storage: EmailEngine encrypts and stores credentials internally
- User-Friendly: Provides a guided authentication flow
Authentication Flow
The user will see:
- Account Type Selection: Choose between IMAP, OAuth2 (Gmail, Outlook), etc.
- Credentials Entry: Enter server details or complete OAuth2 authorization
- Confirmation: See connection status
- Redirect: Automatically redirected back to your CRM
After authentication completes and initial synchronization finishes, the account reaches "connected" state and is ready to use.
Sub-Connections for Sent Mail
Email servers immediately notify EmailEngine about new emails in the primary folder (Inbox), but for secondary folders like Sent Mail, EmailEngine relies on polling. This can cause delays in detecting sent emails.
Problem: If a CRM user sends an email and receives a response within minutes, EmailEngine might detect the reply but not the initial sent email (hasn't polled the Sent folder yet).
Solution: Use sub-connections to treat additional folders as primary, enabling instant notifications.
Configuring Sub-Connections
{
"account": "USER_ID",
"name": "User Name",
"email": "user@example.com",
"subconnections": [
"\\Sent"
],
"redirectUrl": "https://myapp/account/settings.php"
}
Using the special use flag \Sent allows EmailEngine to automatically determine the correct Sent Mail folder path for different email providers.
Important Considerations
- Each sub-connection is an additional IMAP session to the same account
- Providers cap the number of parallel IMAP sessions per account, and the cap differs by provider
- List only the folders that need immediate notification; every other folder is still polled
Read more: Enable Sub-Connections
Listening for Webhooks
Configure Webhook URL
Set up your webhook endpoint in EmailEngine's configuration:
- Navigate to Configuration > Webhooks in EmailEngine and check Enable Webhooks
- Enter your CRM endpoint as the Webhook URL
- Tick the events to deliver. The list is an allowlist with no default, so an instance where nothing is ticked delivers nothing
Event Types (the ones a CRM sync uses):
- messageNew ("New Email"): a message appeared in a folder, incoming and sent alike
- messageDeleted: a message was removed from a folder
- messageBounce: a bounce report arrived for a sent message
- accountAdded and accountDeleted: an account was registered or removed
The full list is on the webhook events reference.
Best Practice: Tick only New Email (messageNew) to keep the volume down. It covers both incoming and sent mail, and it is the one event the registry below is built on.
Create Webhook Handler
Create an endpoint in your CRM that accepts JSON payloads:
<?php
// webhook-handler.php
// Read webhook payload
$payload = json_decode(file_get_contents('php://input'), true);
// Return 2xx quickly, process asynchronously
http_response_code(200);
// Queue for background processing
queueWebhook($payload);
function queueWebhook($payload) {
// Add to job queue (Redis, database, etc.)
// Process later by background worker
}
Important: Always return HTTP 2xx status quickly. Process webhooks asynchronously to avoid blocking EmailEngine.
Classifying New Emails
Understanding Email States
Every email added to a folder appears as "new," even if moved between folders. This creates challenges:
- Moving email from Inbox to Spam: Appears as deletion + new email
- Moving back to Inbox: Appears as another new email
- Email IDs change when messages move between folders
Using Message IDs for Deduplication
Solution: Use the messageId property (from the Message-ID header) to track processed emails.
Example Webhook Payload:
{
"account": "USER_ID",
"date": "2023-04-21T08:08:47.884Z",
"path": "INBOX",
"specialUse": "\\Inbox",
"event": "messageNew",
"data": {
"id": "AAAARgAACMA",
"uid": 2240,
"from": {
"name": "Sender Name",
"address": "sender@example.com"
},
"to": [
{
"name": "",
"address": "user@example.com"
}
],
"subject": "Hello world!",
"messageId": "<01000187a29df5a2@example.com>",
"messageSpecialUse": "\\Inbox",
"threadId": "3d3e3d89-fc5b-4336-a454-a3ce280d849c"
}
}
Key Properties
-
data.messageSpecialUse: Primary special folder for the email\Inbox: Incoming email\Sent: Sent email\Junk: Spam/Junk\Trash: Deletednull: User-created folder
-
data.messageId: Unique identifier from Message-ID header- Use for deduplication
- Remains constant across folders
- Empty messageId usually indicates spam
Identifying Email Direction
function classifyEmail(payload) {
const specialUse = payload.data.messageSpecialUse;
if (specialUse === '\\Inbox') {
return 'incoming';
} else if (specialUse === '\\Sent') {
return 'sent';
} else if (specialUse === '\\Draft') {
return 'draft'; // ignore drafts
} else if (specialUse === '\\Junk' || specialUse === '\\Trash') {
return 'ignore';
} else {
// User folder - could be incoming via filter
return 'incoming';
}
}
Note: Some users have email filters that move specific emails to custom folders. Consider treating non-special folders as incoming emails.
Servers That Provide emailId
Some servers also provide emailId, an identifier that stays the same when a message moves between folders: Gmail over IMAP and over the Gmail API, Microsoft Graph accounts, and IMAP servers that implement the OBJECTID extension. It is absent when the server offers nothing of the kind:
{
"data": {
"emailId": "187a29df5a2",
"messageId": "<01000187a29df5a2@example.com>"
}
}
Use emailId when the payload carries it and fall back to messageId otherwise.
Building a Message Registry
Create a registry to track processed emails and prevent duplicates.