Connect Outlook with Salesforce
Implementation Guide
Overview: Connecting Outlook and Salesforce
The integration between Microsoft Outlook and Salesforce is a mission-critical workflow for any revenue-generating organization that depends on email as a primary channel for prospect and customer communication. Without a formal integration, sales representatives must manually log every sent email, every received reply, and every booked meeting as an Activity record in Salesforce — a process that is reliably ignored, creating CRM data quality problems that cascade into inaccurate forecasting, missed follow-ups, and poor marketing attribution.
There are three distinct implementation patterns for connecting Outlook to Salesforce, and selecting the wrong one for your architecture is a common and costly mistake. The first is the Salesforce Outlook Integration (formerly known as Salesforce for Outlook), which is a client-side add-in that runs inside the Outlook desktop application or Outlook on the web. The second is a server-side integration using the Microsoft Graph API and the Salesforce REST API, typically orchestrated by an iPaaS platform such as Make (formerly Integromat), MuleSoft, or Microsoft Power Automate. The third is Einstein Activity Capture (EAC), which is Salesforce's native background sync engine that requires no user interaction but has significant data retention and visibility limitations that enterprise architects must understand before deploying. This guide covers all three patterns with full implementation detail.
Core Prerequisites
For the Salesforce Outlook Integration (add-in), you need Salesforce Enterprise Edition or above, and your Salesforce org must have the "Outlook Integration" permission set assigned to each user. In Outlook, users must be on Exchange Online (Microsoft 365) or Exchange Server 2016+. The add-in is deployed from the Microsoft 365 Admin Center or directly from AppSource. No OAuth 2.0 configuration is required for end users, but a Salesforce admin must enable the integration under Setup > Outlook Integration and Sync.
For the server-side Graph API + Salesforce REST API pattern, you need an Azure AD App Registration with the following Microsoft Graph API application permissions (not delegated): Mail.Read, Mail.ReadWrite, Calendars.Read, Calendars.ReadWrite, and User.Read.All. These must be granted admin consent by an Azure AD Global Administrator. On the Salesforce side, you need a Connected App configured with the api, refresh_token, and offline_access OAuth scopes. The Salesforce user account used for the server-side integration should be a dedicated integration user with the Salesforce System Administrator or a custom profile that includes Create/Edit/View permissions on Lead, Contact, Opportunity, Task, and EmailMessage objects.
For Einstein Activity Capture, you need Salesforce Sales Cloud with Einstein Activity Capture enabled (included in Sales Cloud Einstein or available as an add-on). Each user must connect their Microsoft 365 mailbox via the EAC setup wizard in their personal settings.
Top Enterprise Use Cases
The highest-value use case is automatic Activity logging for all inbound and outbound email communications between sales reps and Salesforce Contact or Lead records. When a sales rep sends or receives an email to/from a known Salesforce contact, the email is automatically logged as an EmailMessage object associated with the correct Contact, Lead, or Opportunity record — without any manual action.
The second use case is automatic Lead creation from inbound emails. When a new email arrives from an address that does not exist in Salesforce as a Contact or Lead, an automated workflow creates a new Lead record, populates the Email, FirstName, LastName, and LeadSource fields, and assigns it to the rep who received the email or to a round-robin assignment queue.
The third use case is meeting-to-opportunity association. When a sales rep accepts a calendar invitation from an existing Opportunity contact, a Salesforce Event record is automatically created and associated with both the Contact and the Opportunity, updating the Next_Meeting_Date__c custom field and logging it in the Opportunity's activity timeline.
Step-by-Step Implementation Guide
The most robust and customizable approach for enterprise deployments is the server-side integration using Make (formerly Integromat). This approach decouples the integration from the end user's Outlook client, operates on a schedule or webhook trigger, and allows complex conditional logic before writing to Salesforce.
Begin by creating a new Scenario in Make. The trigger module is "Microsoft Office 365 > Watch Emails." Configure it to watch the Inbox folder of a shared mailbox or a specific user's mailbox. The trigger interval should be set to every 15 minutes for near-real-time processing without exceeding Microsoft Graph API throttling limits. The output of this trigger module provides the full email object, including from.emailAddress.address, subject, body.content, receivedDateTime, and the internetMessageId which serves as an idempotency key.
The next module is a "Salesforce > Search Records" action configured to search the Contact object where Email = {{1.from.emailAddress.address}}. If the search returns a record, branch to an "Update Record" path. If it returns no results, add a second "Search Records" module targeting the Lead object with the same email filter. If neither search returns a result, route to a "Create Record" module targeting Lead with the following field mapping:
Email→{{1.from.emailAddress.address}}LastName→ parsed from{{1.from.emailAddress.name}}(use a text parsing function to split on space)LeadSource→ hardcoded toEmailDescription→{{1.subject}}: {{1.bodyPreview}}OwnerId→ the Salesforce User ID of the receiving rep (resolved via a lookup table in Make using the recipient's email address)
For the email activity logging path (when the Contact or Lead is found), add a "Salesforce > Create Record" module targeting the Task object with the following fields:
{
"Subject": "Email: {{1.subject}}",
"WhoId": "{{ContactOrLeadId}}",
"Status": "Completed",
"Priority": "Normal",
"TaskSubtype": "Email",
"Description": "{{1.bodyPreview}}",
"ActivityDate": "{{formatDate(1.receivedDateTime; 'YYYY-MM-DD')}}",
"Type": "Email"
}
For the Microsoft Graph API webhook approach (event-driven rather than scheduled polling), register a subscription at the Graph API endpoint POST https://graph.microsoft.com/v1.0/subscriptions with the following JSON body. This creates a push notification that calls your handler endpoint within seconds of a new email arriving:
{
"changeType": "created",
"notificationUrl": "https://your-integration-service.com/webhooks/outlook/new-email",
"resource": "users/[email protected]/messages",
"expirationDateTime": "2024-12-01T18:23:45.000Z",
"clientState": "your-secret-validation-token"
}
Graph API subscriptions expire and must be renewed before the expirationDateTime. The maximum subscription duration for mail resources is 4230 minutes (approximately 3 days). Implement a scheduled job that calls PATCH https://graph.microsoft.com/v1.0/subscriptions/{id} with a new expirationDateTime every 2 days to prevent subscription expiry.
Common Pitfalls & Troubleshooting
A 401 Unauthorized response from the Microsoft Graph API after initial setup typically indicates that the admin consent grant was applied to delegated permissions instead of application permissions. Server-side integrations running without a logged-in user context require application permissions. In Azure AD, navigate to your App Registration > API Permissions and verify that the permission type column shows "Application" and not "Delegated" for all Graph scopes. Re-grant admin consent after correcting the permission type.
A 429 Too Many Requests from either the Graph API or the Salesforce REST API is the most common production issue for email-heavy organizations. The Microsoft Graph API enforces per-user throttling at approximately 10,000 requests per 10 minutes. The Salesforce REST API enforces daily API call limits based on your edition (e.g., Enterprise Edition allows 1,000 API calls per Salesforce license per day, with a minimum of 1,000,000). Implement exponential backoff in your integration layer and use the Retry-After header value from the 429 response to determine the exact wait duration before retrying.
If duplicate Activity records are being created in Salesforce, the root cause is typically idempotency failure in the polling-based approach. Use the email's internetMessageId field as an external idempotency key. Before creating a Task, query the Task object for an existing record where Description contains or a custom External_Id__c field equals the internetMessageId. If found, skip the creation. A cleaner approach is to create a custom OutlookMessageId__c unique external ID field on the Task object and use Salesforce's upsert operation (PATCH /services/data/vXX.X/sobjects/Task/OutlookMessageId__c/{messageId}) instead of a create.
Einstein Activity Capture's most significant limitation — and the most common source of enterprise escalations — is that EAC-logged activities are stored in a separate data store and are not queryable via SOQL or the Salesforce REST API. They are only visible in the Activity Timeline UI component. This means your BI tools, Apex triggers, and workflow rules cannot access EAC-captured emails. If your organization requires programmatic access to email activity data, do not rely on EAC and implement the server-side API integration instead.