diff --git a/components/EmailComposer.vue b/components/EmailComposer.vue
index d6c6b15..f81f4c3 100644
--- a/components/EmailComposer.vue
+++ b/components/EmailComposer.vue
@@ -253,14 +253,14 @@ const getSignaturePreview = () => {
return `
+

+
${sig.name || 'Your Name'}
${sig.title || 'Your Title'}
${sig.company || 'Company Name'}
${contactLines ? contactLines + '
' : ''}
${userEmail}
-

-
The information in this message is confidential and may be privileged.
It is intended for the addressee alone.
diff --git a/docs/email-system-fixes.md b/docs/email-system-fixes.md
index 5cde386..6e3bfb4 100644
--- a/docs/email-system-fixes.md
+++ b/docs/email-system-fixes.md
@@ -30,6 +30,27 @@
- Updated `update-interest.ts` API to accept both x-tag headers ("094ut234" and "pjnvü1230")
- Now both authenticated and unauthenticated users can save interest updates
+### 5. Email Signature Formatting
+- **Problem**: Logo was appearing below the signature details
+- **Solution**:
+ - Moved Port Nimara logo to the top of the signature
+ - Logo now appears above the name with proper spacing
+
+### 6. Email Refresh Not Showing New Emails
+- **Problem**: New emails from clients weren't appearing after refresh
+- **Solution**:
+ - Enhanced IMAP search to include CC and BCC fields
+ - Now searches in multiple folders: INBOX, Sent, Sent Items, Sent Mail
+ - Better email detection for comprehensive thread retrieval
+
+### 7. EOI Document Generation Issues
+- **Problem**: EOI documents were created but stuck in draft status with non-working links
+- **Solution**:
+ - Fixed response structure to match actual Documenso API response
+ - Added proper document send step to move from draft to active
+ - Changed `sendEmail` to `true` to ensure recipients receive signing emails
+ - Correctly extract signing URLs from the response
+
## Required Environment Variables
Make sure these are set in your `.env` file:
diff --git a/server/api/email/fetch-thread.ts b/server/api/email/fetch-thread.ts
index a19ad7b..54578d2 100644
--- a/server/api/email/fetch-thread.ts
+++ b/server/api/email/fetch-thread.ts
@@ -163,94 +163,116 @@ async function fetchImapEmails(
};
imap.once('ready', () => {
- imap.openBox('INBOX', true, (err, box) => {
- if (err) {
+ // Search in both INBOX and Sent folders
+ const foldersToSearch = ['INBOX', 'Sent', 'Sent Items', 'Sent Mail'];
+ let currentFolderIndex = 0;
+ const allEmails: EmailMessage[] = [];
+
+ const searchNextFolder = () => {
+ if (currentFolderIndex >= foldersToSearch.length) {
cleanup();
- reject(err);
+ resolve(allEmails);
return;
}
- const searchCriteria = [
- ['OR', ['FROM', clientEmail], ['TO', clientEmail]]
- ];
+ const folderName = foldersToSearch[currentFolderIndex];
+ currentFolderIndex++;
- imap.search(searchCriteria, (err, results) => {
+ imap.openBox(folderName, true, (err, box) => {
if (err) {
- cleanup();
- reject(err);
+ console.log(`Folder ${folderName} not found, trying next...`);
+ searchNextFolder();
return;
}
- if (!results || results.length === 0) {
- cleanup();
- resolve(emails);
- return;
- }
+ console.log(`Searching in folder: ${folderName}`);
- const messagesToFetch = results.slice(-limit);
- let messagesProcessed = 0;
-
- const fetch = imap.fetch(messagesToFetch, {
- bodies: '',
- struct: true,
- envelope: true
- });
+ // Search for emails both sent and received with this client
+ const searchCriteria = [
+ 'OR',
+ ['FROM', clientEmail],
+ ['TO', clientEmail],
+ ['CC', clientEmail],
+ ['BCC', clientEmail]
+ ];
- fetch.on('message', (msg, seqno) => {
- msg.on('body', (stream, info) => {
- simpleParser(stream as any, async (err: any, parsed: any) => {
- if (err) {
- console.error('Parse error:', err);
- messagesProcessed++;
- if (messagesProcessed === messagesToFetch.length) {
- cleanup();
- resolve(emails);
+ imap.search(searchCriteria, (err, results) => {
+ if (err) {
+ console.error(`Search error in ${folderName}:`, err);
+ searchNextFolder();
+ return;
+ }
+
+ if (!results || results.length === 0) {
+ console.log(`No emails found in ${folderName}`);
+ searchNextFolder();
+ return;
+ }
+
+ console.log(`Found ${results.length} emails in ${folderName}`);
+ const messagesToFetch = results.slice(-limit);
+ let messagesProcessed = 0;
+
+ const fetch = imap.fetch(messagesToFetch, {
+ bodies: '',
+ struct: true,
+ envelope: true
+ });
+
+ fetch.on('message', (msg, seqno) => {
+ msg.on('body', (stream, info) => {
+ simpleParser(stream as any, async (err: any, parsed: any) => {
+ if (err) {
+ console.error('Parse error:', err);
+ messagesProcessed++;
+ if (messagesProcessed === messagesToFetch.length) {
+ searchNextFolder();
+ }
+ return;
}
- return;
- }
- const email: EmailMessage = {
- id: parsed.messageId || `${Date.now()}-${seqno}`,
- from: parsed.from?.text || '',
- to: Array.isArray(parsed.to)
- ? parsed.to.map((addr: any) => addr.text).join(', ')
- : parsed.to?.text || '',
- subject: parsed.subject || '',
- body: parsed.text || '',
- html: parsed.html || undefined,
- timestamp: parsed.date?.toISOString() || new Date().toISOString(),
- direction: parsed.from?.text.includes(userEmail) ? 'sent' : 'received'
- };
+ const email: EmailMessage = {
+ id: parsed.messageId || `${Date.now()}-${seqno}`,
+ from: parsed.from?.text || '',
+ to: Array.isArray(parsed.to)
+ ? parsed.to.map((addr: any) => addr.text).join(', ')
+ : parsed.to?.text || '',
+ subject: parsed.subject || '',
+ body: parsed.text || '',
+ html: parsed.html || undefined,
+ timestamp: parsed.date?.toISOString() || new Date().toISOString(),
+ direction: parsed.from?.text.toLowerCase().includes(userEmail.toLowerCase()) ? 'sent' : 'received'
+ };
- if (parsed.headers.has('in-reply-to')) {
- email.threadId = parsed.headers.get('in-reply-to') as string;
- }
+ if (parsed.headers.has('in-reply-to')) {
+ email.threadId = parsed.headers.get('in-reply-to') as string;
+ }
- emails.push(email);
- messagesProcessed++;
-
- if (messagesProcessed === messagesToFetch.length) {
- cleanup();
- resolve(emails);
- }
+ allEmails.push(email);
+ messagesProcessed++;
+
+ if (messagesProcessed === messagesToFetch.length) {
+ searchNextFolder();
+ }
+ });
});
});
- });
- fetch.once('error', (err) => {
- console.error('Fetch error:', err);
- cleanup();
- reject(err);
- });
+ fetch.once('error', (err) => {
+ console.error('Fetch error:', err);
+ searchNextFolder();
+ });
- fetch.once('end', () => {
- if (messagesProcessed === 0) {
- cleanup();
- resolve(emails);
- }
+ fetch.once('end', () => {
+ if (messagesProcessed === 0) {
+ searchNextFolder();
+ }
+ });
});
});
- });
+ };
+
+ searchNextFolder();
});
imap.once('error', (err: any) => {
diff --git a/server/api/email/generate-eoi-document.ts b/server/api/email/generate-eoi-document.ts
index 5cfeacb..5259fcb 100644
--- a/server/api/email/generate-eoi-document.ts
+++ b/server/api/email/generate-eoi-document.ts
@@ -10,8 +10,16 @@ interface DocumensoRecipient {
}
interface DocumensoResponse {
- id: string;
- recipients: DocumensoRecipient[];
+ documentId: number;
+ recipients: Array<{
+ recipientId: number;
+ name: string;
+ email: string;
+ token: string;
+ role: 'SIGNER' | 'APPROVER';
+ signingOrder: number;
+ signingUrl: string;
+ }>;
}
export default defineEventHandler(async (event) => {
@@ -186,27 +194,33 @@ export default defineEventHandler(async (event) => {
});
}
- // 3. Setup completion emails
+ // 3. Send document (moves from draft to active and sends emails)
try {
- const completionResponse = await fetch(`${documensoBaseUrl}/api/v1/documents/${documentResponse.id}/send`, {
+ const sendResponse = await fetch(`${documensoBaseUrl}/api/v1/documents/${documentResponse.documentId}/send`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${documensoApiKey}`
},
body: JSON.stringify({
- sendEmail: false,
+ sendEmail: true,
sendCompletionEmails: true
})
});
- if (!completionResponse.ok) {
- console.error('Failed to setup completion emails:', await completionResponse.text());
- // Don't fail the whole process if this fails
+ if (!sendResponse.ok) {
+ const errorText = await sendResponse.text();
+ console.error('Failed to send document:', errorText);
+ throw new Error(`Failed to send document: ${sendResponse.statusText}`);
}
+
+ console.log('Document sent successfully');
} catch (error) {
- console.error('Completion email setup error:', error);
- // Continue anyway
+ console.error('Document send error:', error);
+ throw createError({
+ statusCode: 500,
+ statusMessage: "Document created but failed to send. Please check Documenso dashboard."
+ });
}
// Extract signing URLs from recipients
@@ -261,7 +275,7 @@ export default defineEventHandler(async (event) => {
return {
success: true,
- documentId: documentResponse.id,
+ documentId: documentResponse.documentId,
clientSigningUrl: signingLinks['Client'] || '',
signingLinks: signingLinks
};