/** * @node imap-search * @name IMAP Search * @category email * @version 1.2.0 * @description Search and list emails from an IMAP server with various filters. * @icon search */ const configSchema = { type: 'object', properties: { credentialId: { type: 'string', title: 'IMAP Credential', description: 'Select the IMAP credential to use for authentication', dynamicOptions: { source: 'credentials', filter: { type: 'imap' } } }, mailbox: { type: 'string', title: 'Mailbox', description: 'The mailbox to search (e.g., INBOX, Sent, Drafts)', default: 'INBOX' }, criteria: { type: 'string', title: 'Search Criteria', description: 'IMAP search criteria (e.g., ALL, UNSEEN, FROM user@example.com)', default: 'ALL' }, filterUnread: { type: 'boolean', title: 'Only Unread', description: 'Add UNSEEN filter to search criteria', default: false }, filterFrom: { type: 'string', title: 'Filter by From', description: 'Filter emails from this address (optional)' }, filterSubject: { type: 'string', title: 'Filter by Subject', description: 'Filter emails containing this text in subject (optional)' }, filterSince: { type: 'string', title: 'Since Date', description: 'Filter emails since this date (DD-Mon-YYYY format, e.g., 01-Jan-2024)' }, limit: { type: 'integer', title: 'Limit', description: 'Maximum number of emails to return', default: 50, minimum: 1, maximum: 1000 }, fetchContent: { type: 'boolean', title: 'Fetch Full Content', description: 'Fetch full email content including body and raw data (required for attachment extraction)', default: false }, markAsRead: { type: 'boolean', title: 'Mark as Read', description: 'Mark emails as read after fetching (only applies when Fetch Full Content is enabled)', default: false } }, required: ['credentialId'] }; const inputSchema = { type: 'object', properties: { criteria: { type: 'string', description: 'Override search criteria from input' }, mailbox: { type: 'string', description: 'Override mailbox from input' } } }; const outputSchema = { type: 'object', properties: { uids: { type: 'array', items: { type: 'string' }, description: 'Array of message UIDs' }, count: { type: 'integer', description: 'Number of emails found' }, emails: { type: 'array', description: 'Array of email objects (if fetchContent is enabled)', items: { type: 'object', properties: { uid: { type: 'string', description: 'Unique email identifier' }, subject: { type: 'string' }, from: { type: 'string' }, to: { type: 'string' }, date: { type: 'string' }, body: { type: 'string', description: 'Email body' }, raw: { type: 'string', description: 'Raw email content' }, hasAttachments: { type: 'boolean', description: 'Whether email has attachments' } } } }, mailbox: { type: 'string' }, criteria: { type: 'string' } } }; const outputs = [ { name: 'main', displayName: 'Search Results', type: 'object', color: '#3b82f6' } ]; /** * Check if email has attachments by looking for Content-Disposition: attachment * or multipart content types */ function detectAttachments(rawEmail) { if (!rawEmail) return false; const lower = rawEmail.toLowerCase(); return lower.includes('content-disposition: attachment') || lower.includes('content-disposition:attachment') || (lower.includes('multipart/mixed') && lower.includes('boundary=')); } module.exports = { configSchema, inputSchema, outputSchema, outputs, async execute(config, input, context) { const credentialId = config.credentialId; const mailbox = input.mailbox || config.mailbox || 'INBOX'; const limit = config.limit || 50; const fetchContent = config.fetchContent || false; const markAsRead = config.markAsRead || false; if (!credentialId) { throw new Error('IMAP credential is required'); } // Build search criteria let criteria = input.criteria || config.criteria || 'ALL'; if (config.filterUnread && criteria.indexOf('UNSEEN') === -1) { criteria = criteria === 'ALL' ? 'UNSEEN' : `${criteria} UNSEEN`; } if (config.filterFrom) { criteria += ` FROM "${config.filterFrom}"`; } if (config.filterSubject) { criteria += ` SUBJECT "${config.filterSubject}"`; } if (config.filterSince) { criteria += ` SINCE "${config.filterSince}"`; } // Perform search const searchResult = smartbotic.imap.search({ credentialId, mailbox, criteria, limit }); if (!searchResult.success) { throw new Error(`IMAP search failed: ${searchResult.error}`); } const result = { uids: searchResult.uids, count: searchResult.count, mailbox, criteria }; // Optionally fetch content for each email if (fetchContent && searchResult.uids.length > 0) { result.emails = []; for (const uid of searchResult.uids) { // Use peek: true to avoid marking as read during fetch // Only mark as read explicitly if markAsRead is enabled const fetchResult = smartbotic.imap.fetch({ credentialId, mailbox, uid, peek: !markAsRead // peek=true prevents marking as read }); if (fetchResult.success) { result.emails.push({ uid: fetchResult.uid, subject: fetchResult.subject, from: fetchResult.from, to: fetchResult.to, date: fetchResult.date, body: fetchResult.body, raw: fetchResult.raw, hasAttachments: detectAttachments(fetchResult.raw) }); } } } return result; } };