Skip to content

Commit dc81e30

Browse files
committed
final cleanup
1 parent 26caa7f commit dc81e30

File tree

5 files changed

+71
-43
lines changed

5 files changed

+71
-43
lines changed

apps/sim/app/api/tools/imap/mailboxes/route.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createLogger } from '@sim/logger'
22
import { ImapFlow } from 'imapflow'
33
import { type NextRequest, NextResponse } from 'next/server'
4+
import { getSession } from '@/lib/auth'
45

56
const logger = createLogger('ImapMailboxesAPI')
67

@@ -14,6 +15,11 @@ interface ImapMailboxRequest {
1415
}
1516

1617
export async function POST(request: NextRequest) {
18+
const session = await getSession()
19+
if (!session?.user?.id) {
20+
return NextResponse.json({ success: false, message: 'Unauthorized' }, { status: 401 })
21+
}
22+
1723
try {
1824
const body = (await request.json()) as ImapMailboxRequest
1925
const { host, port, secure, rejectUnauthorized, username, password } = body

apps/sim/lib/webhooks/gmail-polling-service.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,18 +238,20 @@ export async function pollGmailWebhooks() {
238238
}
239239

240240
for (const webhookData of activeWebhooks) {
241-
const promise = enqueue(webhookData)
242-
.then(() => {})
241+
const promise: Promise<void> = enqueue(webhookData)
243242
.catch((err) => {
244243
logger.error('Unexpected error in webhook processing:', err)
245244
failureCount++
246245
})
246+
.finally(() => {
247+
const idx = running.indexOf(promise)
248+
if (idx !== -1) running.splice(idx, 1)
249+
})
247250

248251
running.push(promise)
249252

250253
if (running.length >= CONCURRENCY) {
251-
const completedIdx = await Promise.race(running.map((p, i) => p.then(() => i)))
252-
running.splice(completedIdx, 1)
254+
await Promise.race(running)
253255
}
254256
}
255257

apps/sim/lib/webhooks/imap-polling-service.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,18 +190,21 @@ export async function pollImapWebhooks() {
190190
}
191191

192192
for (const webhookData of activeWebhooks) {
193-
const promise = enqueue(webhookData)
194-
.then(() => {})
193+
const promise: Promise<void> = enqueue(webhookData)
195194
.catch((err) => {
196195
logger.error('Unexpected error in webhook processing:', err)
197196
failureCount++
198197
})
198+
.finally(() => {
199+
// Self-remove from running array when completed
200+
const idx = running.indexOf(promise)
201+
if (idx !== -1) running.splice(idx, 1)
202+
})
199203

200204
running.push(promise)
201205

202206
if (running.length >= CONCURRENCY) {
203-
const completedIdx = await Promise.race(running.map((p, i) => p.then(() => i)))
204-
running.splice(completedIdx, 1)
207+
await Promise.race(running)
205208
}
206209
}
207210

@@ -268,9 +271,19 @@ async function fetchNewEmails(config: ImapWebhookConfig, requestId: string) {
268271
const mailbox = await client.mailboxOpen(mailboxPath)
269272
logger.debug(`[${requestId}] Opened mailbox: ${mailbox.path}, exists: ${mailbox.exists}`)
270273

271-
const rawCriteria = config.searchCriteria || 'UNSEEN'
272-
let searchCriteria: any =
273-
typeof rawCriteria === 'string' ? { [rawCriteria.toLowerCase()]: true } : rawCriteria
274+
// Parse search criteria - expects JSON object from UI
275+
let searchCriteria: any = { unseen: true }
276+
if (config.searchCriteria) {
277+
if (typeof config.searchCriteria === 'object') {
278+
searchCriteria = config.searchCriteria
279+
} else if (typeof config.searchCriteria === 'string') {
280+
try {
281+
searchCriteria = JSON.parse(config.searchCriteria)
282+
} catch {
283+
logger.warn(`[${requestId}] Invalid search criteria JSON, using default`)
284+
}
285+
}
286+
}
274287

275288
const lastUidForMailbox = latestUidByMailbox[mailboxPath] || config.lastProcessedUid
276289

@@ -307,7 +320,7 @@ async function fetchNewEmails(config: ImapWebhookConfig, requestId: string) {
307320
continue
308321
}
309322

310-
messageUids.sort((a, b) => b - a)
323+
messageUids.sort((a, b) => a - b) // Sort ascending to process oldest first
311324
const remainingSlots = maxEmails - totalEmailsCollected
312325
const uidsToProcess = messageUids.slice(0, remainingSlots)
313326

apps/sim/lib/webhooks/outlook-polling-service.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,18 +276,20 @@ export async function pollOutlookWebhooks() {
276276
}
277277

278278
for (const webhookData of activeWebhooks) {
279-
const promise = enqueue(webhookData)
280-
.then(() => {})
279+
const promise: Promise<void> = enqueue(webhookData)
281280
.catch((err) => {
282281
logger.error('Unexpected error in webhook processing:', err)
283282
failureCount++
284283
})
284+
.finally(() => {
285+
const idx = running.indexOf(promise)
286+
if (idx !== -1) running.splice(idx, 1)
287+
})
285288

286289
running.push(promise)
287290

288291
if (running.length >= CONCURRENCY) {
289-
const completedIdx = await Promise.race(running.map((p, i) => p.then(() => i)))
290-
running.splice(completedIdx, 1)
292+
await Promise.race(running)
291293
}
292294
}
293295

apps/sim/triggers/imap/poller.ts

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -135,45 +135,50 @@ export const imapPollingTrigger: TriggerConfig = {
135135
{
136136
id: 'searchCriteria',
137137
title: 'Search Criteria',
138-
type: 'short-input',
139-
placeholder: 'UNSEEN',
140-
description:
141-
'IMAP search criteria (e.g., UNSEEN, FROM "sender@example.com", SUBJECT "report"). Default: UNSEEN',
142-
defaultValue: 'UNSEEN',
138+
type: 'code',
139+
placeholder: '{ "unseen": true }',
140+
description: 'ImapFlow search criteria as JSON object. Default: unseen messages only.',
141+
defaultValue: '{ "unseen": true }',
143142
required: false,
144143
mode: 'trigger',
145144
wandConfig: {
146145
enabled: true,
147146
maintainHistory: true,
148-
prompt: `You are an expert in IMAP search syntax (RFC 3501). Generate IMAP search criteria based on user descriptions.
147+
generationType: 'json-object',
148+
prompt: `Generate ImapFlow search criteria as a JSON object based on the user's description.
149149
150-
IMAP search keys include:
151-
- ALL - All messages
152-
- UNSEEN / SEEN - Unread/read messages
153-
- FLAGGED / UNFLAGGED - Starred/unstarred
154-
- FROM "string" - Sender contains string
155-
- TO "string" - Recipient contains string
156-
- SUBJECT "string" - Subject contains string
157-
- BODY "string" - Body contains string
158-
- TEXT "string" - Headers or body contains string
159-
- BEFORE date / SINCE date / ON date - Date filters (DD-Mon-YYYY, e.g., 01-Jan-2024)
160-
- LARGER n / SMALLER n - Size in bytes
161-
- HEADER field-name "string" - Custom header search
162-
- NOT criteria - Negate
163-
- OR criteria1 criteria2 - Either matches
164-
- (criteria) - Grouping
150+
Available properties (all are optional, combine as needed):
151+
- "unseen": true - Unread messages
152+
- "seen": true - Read messages
153+
- "flagged": true - Starred/flagged messages
154+
- "answered": true - Replied messages
155+
- "deleted": true - Deleted messages
156+
- "draft": true - Draft messages
157+
- "from": "sender@example.com" - From address contains
158+
- "to": "recipient@example.com" - To address contains
159+
- "cc": "cc@example.com" - CC address contains
160+
- "subject": "keyword" - Subject contains
161+
- "body": "text" - Body contains
162+
- "text": "search" - Headers or body contains
163+
- "since": "2024-01-01" - Emails since date (ISO format)
164+
- "before": "2024-12-31" - Emails before date
165+
- "larger": 10240 - Larger than N bytes
166+
- "smaller": 1048576 - Smaller than N bytes
167+
- "header": { "X-Priority": "1" } - Custom header search
168+
- "or": [{ "from": "a@x.com" }, { "from": "b@x.com" }] - OR conditions
169+
- "not": { "from": "spam@x.com" } - Negate condition
165170
166-
Multiple criteria are AND'd together by default.
171+
Multiple properties are combined with AND.
167172
168173
Examples:
169-
- UNSEEN FROM "boss@company.com"
170-
- OR FROM "alice" FROM "bob"
171-
- SINCE 01-Jan-2024 SUBJECT "report"
172-
- NOT SEEN FLAGGED
174+
- Unread from boss: { "unseen": true, "from": "boss@company.com" }
175+
- From Alice or Bob: { "or": [{ "from": "alice@x.com" }, { "from": "bob@x.com" }] }
176+
- Recent with keyword: { "since": "2024-01-01", "subject": "report" }
177+
- Exclude spam: { "unseen": true, "not": { "from": "newsletter@x.com" } }
173178
174179
Current criteria: {context}
175180
176-
Return ONLY the IMAP search criteria, no explanations or markdown.`,
181+
Return ONLY valid JSON, no explanations or markdown.`,
177182
placeholder: 'Describe what emails you want to filter...',
178183
},
179184
},

0 commit comments

Comments
 (0)