Outlook Automation: Email Workflows with n8n and Make.com
Automate your Outlook emails, calendar and tasks.
Is your Outlook inbox overflowing? Are you spending hours sorting, forwarding, and replying to emails? With Outlook automation, you can automate these routine tasks. In this guide, we show you practical workflows for more productive email management.
Why Automate Outlook?
Typical Time Wasters:| Task | Manual Effort | Automated |
|---|---|---|
| Sorting emails | 30 min/day | Automatic |
| Standard replies | 1h/day | Template + Trigger |
| Forwarding to team | 20 min/day | Rule-based |
| Follow-up reminders | Forgotten... | Automatic |
| Attachment processing | 15 min/day | Instant |
Outlook Automation Options
1. Outlook Rules (Built-in)
For simple automations directly in Outlook:
- Move emails to folders
- Forward
- Categorize
- Notifications
2. Power Automate (Microsoft)
Microsoft's automation platform:
- Deep Outlook integration
- Many templates
- Within the Microsoft 365 ecosystem
3. n8n / Make.com (More Flexible)
For complex workflows and external integrations:
- Connect to any apps
- Complex logic possible
- More control
Step 1: Connect Outlook with n8n
Setting up Microsoft OAuth
- Azure Portal → App registrations
- New registration
- Redirect URI: https://n8n.your-domain.com/rest/oauth2-credential/callback
- Mail.Read, Mail.Send, Mail.ReadWrite
- For calendar: Calendars.ReadWrite
- Credentials → Microsoft Outlook OAuth2 API
- Enter Client ID and Secret
- Authorize
IMAP/SMTP Alternative
For simpler setups without OAuth:
IMAP (Receiving):
- Server: outlook.office365.com
- Port: 993
- SSL: Yes
SMTP (Sending):
- Server: smtp.office365.com
- Port: 587
- TLS: Yes
Workflow 1: Intelligent Email Sorting
The Workflow
New email received
↓
Analyze sender/subject
↓
Switch:
├─ From customer → #customers folder + CRM
├─ Invoice → #accounting + accounting software
├─ Support → Create ticket
└─ Newsletter → Archive / Delete
n8n Implementation
Node 1: Microsoft Outlook Trigger// Trigger on new email
{
"resource": "message",
"operation": "getAll",
"filters": {
"isRead": false // Only unread
}
}
Node 2: Classification
// Node: Code
const email = $json;
const from = email.from.emailAddress.address.toLowerCase();
const subject = email.subject.toLowerCase();
// Sender-based classification
if (from.includes('@customer1.com') || from.includes('@customer2.com')) {
return { category: 'customer', priority: 'high' };
}
// Subject-based classification
if (subject.includes('invoice') || subject.includes('bill')) {
return { category: 'invoice', priority: 'medium' };
}
if (subject.includes('support') || subject.includes('help')) {
return { category: 'support', priority: 'high' };
}
if (from.includes('newsletter') || from.includes('noreply')) {
return { category: 'newsletter', priority: 'low' };
}
return { category: 'other', priority: 'normal' };
Node 3: Move to Folder
// Node: Microsoft Outlook - Move Message
{
"messageId": "{{ $json.id }}",
"destinationFolderId": "{{ $json.category === 'customer' ? 'FOLDER_ID_CUSTOMERS' : 'INBOX' }}"
}
Workflow 2: Auto-Responder with AI
The Workflow
New support email
↓
AI analyzes request
↓
Find matching response from KB
↓
Create draft
↓
Submit for review OR
Send automatically (simple cases)
Implementation with OpenAI
Node: Create Email Draft// Node: OpenAI;const prompt =
You are a friendly customer service representative.
Analyze this email and create an appropriate response.
Email:
From: ${$json.from.emailAddress.address}
Subject: ${$json.subject}
Content: ${$json.body.content}
Rules:
- Reply in English
- Be polite and helpful
- For complex questions: Refer to the support team
- Signature: "Best regards, Your Support Team"
// OpenAI Completion
const response = await openai.chat({
model: "gpt-4",
messages: [{ role: "user", content: prompt }]
});
return { draftReply: response.content };
// Node: Microsoft Outlook - Create Draft
{
"subject": "Re: {{ $json.subject }}",
"body": {
"contentType": "HTML",
"content": "{{ $json.draftReply }}"
},
"toRecipients": [
{ "emailAddress": { "address": "{{ $json.from.emailAddress.address }}" } }
]
}
Workflow 3: Attachment Processing
The Workflow
Email with attachment
↓
Check attachment type
↓
PDF Invoice → OCR → Accounting software
Excel Report → Google Sheets
Image → Compress → Drive
Implementation
// Node: Code - Process attachments
const attachments = $json.attachments || [];
for (const attachment of attachments) {
const filename = attachment.name.toLowerCase();
const contentType = attachment.contentType;
if (filename.endsWith('.pdf')) {
return { type: 'pdf', action: 'process_invoice', attachment };
}
if (filename.endsWith('.xlsx') || filename.endsWith('.csv')) {
return { type: 'spreadsheet', action: 'import_to_sheets', attachment };
}
if (contentType.startsWith('image/')) {
return { type: 'image', action: 'save_to_drive', attachment };
}
}
return { type: 'other', action: 'archive', attachment: null };
Workflow 4: Follow-up Reminder
The Workflow
Email sent
↓
Marked as important?
↓
Yes: Set reminder in 3 days
↓
[After 3 days]
↓
Reply received?
No → Send reminder
Implementation
// Node 1: Send and track email
const sentEmail = await sendEmail({
to: recipient,
subject: subject,
body: body
});
// Save to database
await saveToDb('email_tracking', {
messageId: sentEmail.id,
recipient: recipient,
subject: subject,
sentAt: new Date(),
followUpDate: addDays(new Date(), 3),
status: 'awaiting_reply'
});
// Node 2: Daily check (Schedule Trigger)
const pendingFollowUps = await getFromDb('email_tracking', {
status: 'awaiting_reply',
followUpDate: { $lte: new Date() }
});
for (const email of pendingFollowUps) {
// Check if reply was received
const hasReply = await checkForReply(email.messageId);
if (!hasReply) {
// Reminder to yourself
await sendTeamsNotification(Follow-up needed: ${email.subject});
} else {
await updateDb('email_tracking', email.id, { status: 'replied' });
}
}
Workflow 5: Automate Meeting Invitations
The Workflow
New lead (CRM)
↓
Find available slots (Calendar)
↓
Email with suggested times
↓
Link to Calendly/Booking
Calendar Integration
// Node: Microsoft Outlook - Find Available Slots
{
"resource": "calendar",
"operation": "findMeetingTimes",
"attendees": [
{ "emailAddress": { "address": "{{ $json.leadEmail }}" } }
],
"timeConstraint": {
"timeslots": [
{
"start": { "dateTime": "{{ $now.plus(1, 'day').toISO() }}" },
"end": { "dateTime": "{{ $now.plus(7, 'days').toISO() }}" }
}
]
},
"meetingDuration": "PT1H"
}
Make.com: Outlook Modules
Available Modules
| Module | Function |
|---|---|
| Watch Emails | Trigger on new emails |
| Get an Email | Retrieve email |
| Send an Email | Send email |
| Create a Draft | Create draft |
| Move an Email | Move |
| List Attachments | List attachments |
| Download Attachment | Download attachment |
Example Scenario
Outlook (Watch Emails)
↓
Filter: From @important-customer.com
↓
Slack: Notification
↓
Google Sheets: Log
↓
Outlook: Mark as read
Advanced Patterns
Email Parsing for Structured Data
// Parse order confirmations
const body = $json.body.content;
// Regex for order number
const orderMatch = body.match(/Order Number:\s*(\d+)/i);
const orderId = orderMatch ? orderMatch[1] : null;
// Regex for amount
const amountMatch = body.match(/Total Amount:\s<em>\$?([\d,]+\.?\d</em>)/i);
const amount = amountMatch ? parseFloat(amountMatch[1].replace(',', '')) : null;
return { orderId, amount };
Spam Detection
// Simple spam heuristics
const spamIndicators = [
'unsubscribe',
'click here',
'limited time',
'act now',
'winner'
];
const body = $json.body.content.toLowerCase();
const subject = $json.subject.toLowerCase();
let spamScore = 0;
for (const indicator of spamIndicators) {
if (body.includes(indicator) || subject.includes(indicator)) {
spamScore += 1;
}
}
return { isSpam: spamScore >= 2, spamScore };
Thread Summary
// Summarize email thread with AIFrom: ${m.from}\n${m.body}const thread = $json.conversationThread;
const prompt =
Summarize this email thread:
${thread.map(m =>
).join('\n---\n')};Give me:
Main topic Open items Next steps const summary = await openai.chat({ messages: [{ role: 'user', content: prompt }] });
return { summary: summary.content };
Best Practices
1. Batch Processing
// Process emails in batches, not individually
const emails = await getUnreadEmails(50); // Max 50
for (const batch of chunk(emails, 10)) {
await processEmails(batch);
await wait(1000); // Respect rate limits
}
2. Fault Tolerance
// Email processing must not fail
try {
await processEmail(email);
} catch (error) {
console.error(Failed to process ${email.id}:, error);
await moveToFolder(email.id, 'ProcessingErrors');
await alertAdmin(error);
}
3. Audit Trail
// Log all actions
await logAction({
emailId: email.id,
action: 'moved_to_folder',
folder: targetFolder,
timestamp: new Date(),
reason: classificationResult.reason
});
Costs
| Solution | Cost |
|---|---|
| Outlook Rules | Free |
| Power Automate | Included in M365 |
| n8n Cloud | From $20/month |
| Make.com | From $9/month |
Conclusion
Outlook automation saves time daily:
- Intelligent sorting
- Automatic replies
- Attachment processing
- Follow-up tracking
Next Steps
We support you with Outlook automation - from setup to productive use.