Outlook Calendar Load + HubSpot Deal Velocity: Weekly Ops Digest to Microsoft Teams
Every Monday at 07:30, your revenue team gets one Teams card: last week's deal pipeline movement next to each rep's actual meeting load — so you stop guessing whether low close rates are a pipeline problem or a capacity problem.
The stack in the order it runs — data flows from the source through to where it lands.
Sales leaders waste hours every week pulling two reports by hand: HubSpot pipeline changes and Outlook calendar utilization. Then they stare at CRM data with zero visibility into whether reps had the capacity to execute in the first place. That correlation — deal velocity against meeting volume — is the insight that actually tells you whether to coach, hire, or fix the pipeline. Nobody does it because it means merging two data sources that don't talk to each other.
HubSpot is the right CRM source here. Its API has clean deal stage history endpoints that return stage transitions with timestamps, not just current state. Outlook's Microsoft Graph API exposes calendar event counts, durations, and attendees in a structured format — Gmail's API makes that same data significantly harder to extract. Make (formerly Integromat) handles Graph's OAuth complexity better than n8n does in the current stable release, and has a native HubSpot module so you're not hand-rolling API calls.
Google Sheets is the aggregation layer. Ops folks who want to spot-check the underlying data can do it without touching the automation. Claude writes the narrative paragraph so the Teams message reads like an ops memo, not a spreadsheet export.
Skip this if your team is fully on Google Workspace — swap Outlook for Google Calendar, replace the Graph API calls with Google Calendar API, and the architecture is identical. Don't use this if your HubSpot plan doesn't include the Deals API; check your tier first. And if you have fewer than 3 reps or fewer than 10 deals a week, the correlation isn't meaningful — just read HubSpot manually.
The stack (5)
Mail + calendar at the center of most companies.
Graph API turns the inbox/calendar into a programmable source for ops automations.
Chat + channels for Microsoft-365 shops.
If the company is on Outlook/365, Teams is where reports get read — push there, not a separate tool.
How it runs
- 1
Register an Azure app for Microsoft Graph access
Go to portal.azure.com → Azure Active Directory → App Registrations → New Registration. Name it 'Ops Digest Bot'. Under API Permissions, add Microsoft Graph → Delegated → 'Calendars.Read' and 'User.Read.All'. Grant admin consent. Generate a client secret under Certificates & Secrets. Write down your Client ID, Tenant ID, and Client Secret — you'll need all three in Make. This is the step most people skip and then wonder why Graph keeps returning 403s.
- 2
Build the HubSpot deal pull in Make
Create a new Make scenario. Set the trigger to Schedule → every Monday at 07:30. Add a HubSpot 'Search CRM Objects' module for object type 'deals'. Filter by 'hs_lastmodifieddate' greater than 7 days ago. Request these properties: dealname, dealstage, amount, closedate, hubspot_owner_id, and hs_date_entered_[stage] for each relevant stage. That gives you every deal that moved stages last week. Run a Make Array Aggregator to group results by owner_id — you'll need that grouping when you correlate against calendar data per rep.
- 3
Pull calendar event counts per rep from Microsoft Graph
Add an HTTP module in Make: method GET, URL 'https://graph.microsoft.com/v1.0/users/USER_ID/calendarView', query params 'startDateTime' and 'endDateTime' set to last Monday and last Sunday using Make's date functions ({{formatDate(addDays(now; -7); 'YYYY-MM-DDTHH:mm:ss')}}). Add the Authorization header with your OAuth token from the connection you set up in step 1. Repeat this module per rep by running a Make Iterator over your rep list. Store rep email, total_meetings, and total_meeting_hours as outputs. Filter out internal 1:1s by checking attendee count > 1.
- 4
Aggregate into Google Sheets for the audit trail
Add a Google Sheets 'Add Row' module targeting a sheet called 'Weekly Ops Log'. Columns: Week_Start, Rep_Name, Deals_Moved_Forward, Deals_Stuck, Pipeline_Added ($), Meetings_Count, Meeting_Hours, Avg_Deal_Velocity_Days. Deals_Moved_Forward = count of deals where dealstage changed to a later stage. Deals_Stuck = deals unmodified for more than 14 days. Meeting_Hours = sum of event durations from Graph. When someone questions the Claude summary, this sheet is where you point them.
- 5
Compute team-level summary metrics
Add a Make aggregator that rolls all rep rows into a single team summary: Total_Pipeline_Added, Total_Deals_Closed_Won, Total_Deals_Closed_Lost, Win_Rate (Closed_Won divided by Closed_Won plus Closed_Lost), Team_Total_Meetings, and a 'Capacity_Flag' boolean that flips true if any rep logged more than 25 hours of meetings last week. That 25-hour threshold is a heuristic for reps who were too over-scheduled to actually execute on deals. These team metrics are what you'll feed into the Claude prompt.
- 6
Generate the narrative with Claude
Add an HTTP module: POST to https://api.anthropic.com/v1/messages, model claude-3-5-sonnet-20241022. Build a prompt that passes all team-level metrics and the per-rep table as a structured list. The instruction to Claude: 'You are a sales ops analyst. Write a 4-sentence weekly digest for a sales leader. Lead with pipeline added and win rate. Call out any rep where deal velocity is low AND meeting load is high — that is a capacity problem. Call out any rep where both are low — that is a different problem. Be direct, use the numbers, no filler.' Set max_tokens to 300.
- 7
Post the Adaptive Card to Microsoft Teams
Add an HTTP module POSTing to your Teams channel incoming webhook URL. Build an Adaptive Card with three sections: (1) Team Summary — pipeline added, win rate, deals closed; (2) Per-Rep Table — rep name, deals moved, meetings, hours, velocity; (3) Claude's narrative in a TextBlock with wrap: true. Color code the win rate: green above 30%, yellow for 20–30%, red below 20%. Post to your #sales-ops channel. Keep the card under 28KB — Teams silently drops anything larger and gives you no error.
- 8
Add a Slack fallback for teammates not on Teams
If ops or finance lives in Slack while sales lives in Teams, add a parallel branch in Make that posts a stripped-down version — just the Claude narrative plus three top-line numbers — to a Slack channel via webhook. It's a 10-minute addition to the scenario. Use Make's Router module to branch right after the Claude call: one branch to Teams, one to Slack. This kills the 'I don't use Teams' excuse before it starts.
Want me to build this for you instead?
Product Audit and CTO Mode run out of this same thinking. If you’re reading this thinking “I want this, but in my product” — let’s talk.
See servicesMore like this
Gmail Thread Aging + Stripe Invoice Overdue: Unified AR Follow-Up Digest to Slack via Zapier
Surface overdue Stripe invoices and the exact age of your last Gmail thread with that customer — every morning at 8:30, automatically — so AR follow-up stops living in someone's head.
Intercom Ticket Volume + Razorpay Failed Payments: Daily Support-Cost-per-Revenue Alert to Slack via Zapier
Catch the support cost blowout from Razorpay failed payments before your agents are already buried.
Google Analytics 4 + HubSpot Lifecycle Stage: Weekly Acquisition-Quality Digest to Slack via Pipedream with Claude Narrative
Stop reporting traffic numbers. Report whether the traffic you paid for last week actually became pipeline — with a one-paragraph executive summary written by Claude.