Skip to content

Commit 5f8d769

Browse files
committed
feat(tools): added support for imap trigger
1 parent 79be435 commit 5f8d769

File tree

17 files changed

+1336
-14
lines changed

17 files changed

+1336
-14
lines changed

apps/docs/components/icons.tsx

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,57 @@ export function MailIcon(props: SVGProps<SVGSVGElement>) {
295295
)
296296
}
297297

298+
export function MailServerIcon(props: SVGProps<SVGSVGElement>) {
299+
return (
300+
<svg
301+
{...props}
302+
width='24'
303+
height='24'
304+
viewBox='0 0 24 24'
305+
fill='none'
306+
xmlns='http://www.w3.org/2000/svg'
307+
>
308+
{/* Server/inbox icon with mail symbol */}
309+
<rect
310+
x='3'
311+
y='4'
312+
width='18'
313+
height='16'
314+
rx='2'
315+
stroke='currentColor'
316+
strokeWidth='2'
317+
strokeLinecap='round'
318+
strokeLinejoin='round'
319+
/>
320+
<path
321+
d='M3 8L10.89 13.26C11.2187 13.4793 11.6049 13.5963 12 13.5963C12.3951 13.5963 12.7813 13.4793 13.11 13.26L21 8'
322+
stroke='currentColor'
323+
strokeWidth='2'
324+
strokeLinecap='round'
325+
strokeLinejoin='round'
326+
/>
327+
<line
328+
x1='7'
329+
y1='16'
330+
x2='7'
331+
y2='16'
332+
stroke='currentColor'
333+
strokeWidth='2'
334+
strokeLinecap='round'
335+
/>
336+
<line
337+
x1='10'
338+
y1='16'
339+
x2='10'
340+
y2='16'
341+
stroke='currentColor'
342+
strokeWidth='2'
343+
strokeLinecap='round'
344+
/>
345+
</svg>
346+
)
347+
}
348+
298349
export function CodeIcon(props: SVGProps<SVGSVGElement>) {
299350
return (
300351
<svg
@@ -4284,20 +4335,12 @@ export function RssIcon(props: SVGProps<SVGSVGElement>) {
42844335

42854336
export function SpotifyIcon(props: SVGProps<SVGSVGElement>) {
42864337
return (
4287-
<svg
4288-
{...props}
4289-
width='386'
4290-
height='386'
4291-
viewBox='100 100 186 186'
4292-
fill='none'
4293-
xmlns='http://www.w3.org/2000/svg'
4294-
xmlnsXlink='http://www.w3.org/1999/xlink'
4295-
>
4296-
<image
4297-
width='386'
4298-
height='386'
4299-
xlinkHref='data:image/png;base64,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'
4338+
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 496 512'>
4339+
<path
4340+
fill='#1ed760'
4341+
d='M248 8C111.1 8 0 119.1 0 256s111.1 248 248 248 248-111.1 248-248S384.9 8 248 8Z'
43004342
/>
4343+
<path d='M406.6 231.1c-5.2 0-8.4-1.3-12.9-3.9-71.2-42.5-198.5-52.7-280.9-29.7-3.6 1-8.1 2.6-12.9 2.6-13.2 0-23.3-10.3-23.3-23.6 0-13.6 8.4-21.3 17.4-23.9 35.2-10.3 74.6-15.2 117.5-15.2 73 0 149.5 15.2 205.4 47.8 7.8 4.5 12.9 10.7 12.9 22.6 0 13.6-11 23.3-23.2 23.3zm-31 76.2c-5.2 0-8.7-2.3-12.3-4.2-62.5-37-155.7-51.9-238.6-29.4-4.8 1.3-7.4 2.6-11.9 2.6-10.7 0-19.4-8.7-19.4-19.4s5.2-17.8 15.5-20.7c27.8-7.8 56.2-13.6 97.8-13.6 64.9 0 127.6 16.1 177 45.5 8.1 4.8 11.3 11 11.3 19.7-.1 10.8-8.5 19.5-19.4 19.5zm-26.9 65.6c-4.2 0-6.8-1.3-10.7-3.6-62.4-37.6-135-39.2-206.7-24.5-3.9 1-9 2.6-11.9 2.6-9.7 0-15.8-7.7-15.8-15.8 0-10.3 6.1-15.2 13.6-16.8 81.9-18.1 165.6-16.5 237 26.2 6.1 3.9 9.7 7.4 9.7 16.5s-7.1 15.4-15.2 15.4z' />
43014344
</svg>
43024345
)
43034346
}

apps/docs/components/ui/icon-mapping.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import {
5858
LinkupIcon,
5959
MailchimpIcon,
6060
MailgunIcon,
61+
MailServerIcon,
6162
Mem0Icon,
6263
MicrosoftExcelIcon,
6364
MicrosoftOneDriveIcon,
@@ -165,6 +166,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
165166
huggingface: HuggingFaceIcon,
166167
hunter: HunterIOIcon,
167168
image_generator: ImageIcon,
169+
imap: MailServerIcon,
168170
incidentio: IncidentioIcon,
169171
intercom: IntercomIcon,
170172
jina: JinaAIIcon,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
title: IMAP Email
3+
description: Trigger workflows when new emails arrive via IMAP (works with any email provider)
4+
---
5+
6+
import { BlockInfoCard } from "@/components/ui/block-info-card"
7+
8+
<BlockInfoCard
9+
type="imap"
10+
color="#6366F1"
11+
/>
12+
13+
{/* MANUAL-CONTENT-START:intro */}
14+
The IMAP Email trigger allows your Sim workflows to start automatically whenever a new email is received in any mailbox that supports the IMAP protocol. This works with Gmail, Outlook, Yahoo, and most other email providers.
15+
16+
With the IMAP trigger, you can:
17+
18+
- **Automate email processing**: Start workflows in real time when new messages arrive in your inbox.
19+
- **Filter by sender, subject, or folder**: Configure your trigger to react only to emails that match certain conditions.
20+
- **Extract and process attachments**: Automatically download and use file attachments in your automated flows.
21+
- **Parse and use email content**: Access the subject, sender, recipients, full body, and other metadata in downstream workflow steps.
22+
- **Integrate with any email provider**: Works with any service that provides standard IMAP access, without vendor lock-in.
23+
- **Trigger on unread, flagged, or custom criteria**: Set up advanced filters for the kinds of emails that start your workflows.
24+
25+
With Sim, the IMAP integration gives you the power to turn email into an actionable source of automation. Respond to customer inquiries, process notifications, kick off data pipelines, and more—directly from your email inbox, with no manual intervention.
26+
{/* MANUAL-CONTENT-END */}
27+
28+
29+
## Usage Instructions
30+
31+
Connect to any email server via IMAP protocol to trigger workflows when new emails are received. Supports Gmail, Outlook, Yahoo, and any other IMAP-compatible email provider.
32+
33+
34+
35+
36+
37+
## Notes
38+
39+
- Category: `triggers`
40+
- Type: `imap`

apps/docs/content/docs/en/tools/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"huggingface",
4343
"hunter",
4444
"image_generator",
45+
"imap",
4546
"incidentio",
4647
"intercom",
4748
"jina",
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { createLogger } from '@sim/logger'
2+
import { ImapFlow } from 'imapflow'
3+
import { type NextRequest, NextResponse } from 'next/server'
4+
5+
const logger = createLogger('ImapMailboxesAPI')
6+
7+
interface ImapMailboxRequest {
8+
host: string
9+
port: number
10+
secure: boolean
11+
rejectUnauthorized: boolean
12+
username: string
13+
password: string
14+
}
15+
16+
export async function POST(request: NextRequest) {
17+
try {
18+
const body = (await request.json()) as ImapMailboxRequest
19+
const { host, port, secure, rejectUnauthorized, username, password } = body
20+
21+
if (!host || !username || !password) {
22+
return NextResponse.json(
23+
{ success: false, message: 'Missing required fields: host, username, password' },
24+
{ status: 400 }
25+
)
26+
}
27+
28+
const client = new ImapFlow({
29+
host,
30+
port: port || 993,
31+
secure: secure ?? true,
32+
auth: {
33+
user: username,
34+
pass: password,
35+
},
36+
tls: {
37+
rejectUnauthorized: rejectUnauthorized ?? true,
38+
},
39+
logger: false,
40+
})
41+
42+
try {
43+
await client.connect()
44+
45+
// List all mailboxes
46+
const listResult = await client.list()
47+
const mailboxes = listResult.map((mailbox) => ({
48+
path: mailbox.path,
49+
name: mailbox.name,
50+
delimiter: mailbox.delimiter,
51+
}))
52+
53+
await client.logout()
54+
55+
// Sort mailboxes: INBOX first, then alphabetically
56+
mailboxes.sort((a, b) => {
57+
if (a.path === 'INBOX') return -1
58+
if (b.path === 'INBOX') return 1
59+
return a.path.localeCompare(b.path)
60+
})
61+
62+
return NextResponse.json({
63+
success: true,
64+
mailboxes,
65+
})
66+
} catch (error) {
67+
// Make sure to close connection on error
68+
try {
69+
await client.logout()
70+
} catch {
71+
// Ignore logout errors
72+
}
73+
throw error
74+
}
75+
} catch (error) {
76+
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
77+
logger.error('Error fetching IMAP mailboxes:', errorMessage)
78+
79+
// Provide user-friendly error messages
80+
let userMessage = 'Failed to connect to IMAP server'
81+
if (
82+
errorMessage.includes('AUTHENTICATIONFAILED') ||
83+
errorMessage.includes('Invalid credentials')
84+
) {
85+
userMessage = 'Invalid username or password. For Gmail, use an App Password.'
86+
} else if (errorMessage.includes('ENOTFOUND') || errorMessage.includes('getaddrinfo')) {
87+
userMessage = 'Could not find IMAP server. Please check the hostname.'
88+
} else if (errorMessage.includes('ECONNREFUSED')) {
89+
userMessage = 'Connection refused. Please check the port and SSL settings.'
90+
} else if (errorMessage.includes('certificate') || errorMessage.includes('SSL')) {
91+
userMessage =
92+
'TLS/SSL error. Try disabling "Verify TLS Certificate" for self-signed certificates.'
93+
} else if (errorMessage.includes('timeout')) {
94+
userMessage = 'Connection timed out. Please check your network and server settings.'
95+
}
96+
97+
return NextResponse.json({ success: false, message: userMessage }, { status: 500 })
98+
}
99+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { createLogger } from '@sim/logger'
2+
import { nanoid } from 'nanoid'
3+
import { type NextRequest, NextResponse } from 'next/server'
4+
import { verifyCronAuth } from '@/lib/auth/internal'
5+
import { acquireLock, releaseLock } from '@/lib/core/config/redis'
6+
import { pollImapWebhooks } from '@/lib/webhooks/imap-polling-service'
7+
8+
const logger = createLogger('ImapPollingAPI')
9+
10+
export const dynamic = 'force-dynamic'
11+
export const maxDuration = 180 // Allow up to 3 minutes for polling to complete
12+
13+
const LOCK_KEY = 'imap-polling-lock'
14+
const LOCK_TTL_SECONDS = 180 // Same as maxDuration (3 min)
15+
16+
export async function GET(request: NextRequest) {
17+
const requestId = nanoid()
18+
logger.info(`IMAP webhook polling triggered (${requestId})`)
19+
20+
let lockValue: string | undefined
21+
22+
try {
23+
const authError = verifyCronAuth(request, 'IMAP webhook polling')
24+
if (authError) {
25+
return authError
26+
}
27+
28+
lockValue = requestId // unique value to identify the holder
29+
const locked = await acquireLock(LOCK_KEY, lockValue, LOCK_TTL_SECONDS)
30+
31+
if (!locked) {
32+
return NextResponse.json(
33+
{
34+
success: true,
35+
message: 'Polling already in progress – skipped',
36+
requestId,
37+
status: 'skip',
38+
},
39+
{ status: 202 }
40+
)
41+
}
42+
43+
const results = await pollImapWebhooks()
44+
45+
return NextResponse.json({
46+
success: true,
47+
message: 'IMAP polling completed',
48+
requestId,
49+
status: 'completed',
50+
...results,
51+
})
52+
} catch (error) {
53+
logger.error(`Error during IMAP polling (${requestId}):`, error)
54+
return NextResponse.json(
55+
{
56+
success: false,
57+
message: 'IMAP polling failed',
58+
error: error instanceof Error ? error.message : 'Unknown error',
59+
requestId,
60+
},
61+
{ status: 500 }
62+
)
63+
} finally {
64+
if (lockValue) {
65+
await releaseLock(LOCK_KEY, lockValue).catch(() => {})
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)