Switch n8n email from Resend API to Mailcow SMTP

Replace all Resend HTTP API calls with n8n built-in emailSend
nodes using Mailcow SMTP at the SMTP server.
Add SMTP env vars and n8n API key to docker-compose config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-02-10 00:30:05 +00:00
parent 746ae71601
commit d354e3d2d9
4 changed files with 69 additions and 87 deletions

View File

@ -31,8 +31,15 @@ services:
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=${N8N_DB_PASSWORD:-***REDACTED_DB_PASS***}
- TWENTY_API_KEY=${TWENTY_API_KEY}
- RESEND_API_KEY=${RESEND_API_KEY}
- LISTMONK_CREDENTIALS=${LISTMONK_CREDENTIALS}
- N8N_SMTP_HOST=***REDACTED_SMTP_HOST***
- N8N_SMTP_PORT=587
- N8N_SMTP_USER=${SMTP_USER}
- N8N_SMTP_PASS=${SMTP_PASS}
- N8N_SMTP_SENDER=${SMTP_SENDER:-***REDACTED_EMAIL***}
- N8N_EMAIL_MODE=smtp
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- n8n-cosmolocal-data:/home/node/.n8n
labels:

View File

@ -48,31 +48,24 @@
},
{
"parameters": {
"method": "POST",
"url": "https://api.resend.com/emails",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{ $env.RESEND_API_KEY }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"from\": \"Cosmolocal Foundation <***REDACTED_EMAIL***>\",\n \"to\": [\"{{ $json.email }}\"],\n \"subject\": \"Welcome to the Cosmolocal Foundation\",\n \"html\": \"<h2>Welcome, {{ $json.firstName }}!</h2><p>Thank you for connecting with the Cosmolocal Foundation. We're building a world where local communities thrive within regenerative economies, connected through global knowledge-sharing and commons-based collaboration.</p><p><strong>\\\"What is heavy should be local, and what is light should be global and shared.\\\"</strong></p><p>Here's what we're working on:</p><ul><li><strong>Decentralized Governance</strong> — Transparent, community-led decision-making</li><li><strong>Open Knowledge Commons</strong> — Sharing sustainable production methods globally</li><li><strong>Commons-Compatible Capital</strong> — Financing transformative local projects</li><li><strong>Cosmolocal Coordination</strong> — Connecting local efforts into a global network</li></ul><p>We'll be in touch with updates on our progress and opportunities to get involved.</p><p>Warm regards,<br/>The Cosmolocal Foundation Team</p><p style='color:#78716c;font-size:12px;'>cosmolocal.world</p>\"\n}",
"fromEmail": "={{ $env.N8N_SMTP_SENDER }}",
"toEmail": "={{ $json.email }}",
"subject": "Welcome to the Cosmolocal Foundation",
"emailType": "html",
"html": "<h2>Welcome, {{ $json.firstName }}!</h2><p>Thank you for connecting with the Cosmolocal Foundation. We're building a world where local communities thrive within regenerative economies, connected through global knowledge-sharing and commons-based collaboration.</p><p><strong>\"What is heavy should be local, and what is light should be global and shared.\"</strong></p><p>Here's what we're working on:</p><ul><li><strong>Decentralized Governance</strong> — Transparent, community-led decision-making</li><li><strong>Open Knowledge Commons</strong> — Sharing sustainable production methods globally</li><li><strong>Commons-Compatible Capital</strong> — Financing transformative local projects</li><li><strong>Cosmolocal Coordination</strong> — Connecting local efforts into a global network</li></ul><p>We'll be in touch with updates on our progress and opportunities to get involved.</p><p>Warm regards,<br/>The Cosmolocal Foundation Team</p><p style='color:#78716c;font-size:12px;'>cosmolocal.world</p>",
"options": {}
},
"id": "send-welcome-email",
"name": "Send Welcome Email (Day 0)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [680, 300]
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [680, 300],
"credentials": {
"smtp": {
"id": "mailcow-smtp",
"name": "Mailcow SMTP"
}
}
},
{
"parameters": {
@ -87,31 +80,24 @@
},
{
"parameters": {
"method": "POST",
"url": "https://api.resend.com/emails",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{ $env.RESEND_API_KEY }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"from\": \"Cosmolocal Foundation <***REDACTED_EMAIL***>\",\n \"to\": [\"{{ $('Extract Contact Fields').item.json.email }}\"],\n \"subject\": \"Our Strategic Priorities — How We're Building Change\",\n \"html\": \"<h2>Hi {{ $('Extract Contact Fields').item.json.firstName }},</h2><p>We wanted to share more about our strategic approach to systemic transformation.</p><p>The Cosmolocal Foundation is executing on eight key initiatives:</p><ol><li><strong>Mapping Regenerative Communities</strong> — Cataloging eco-villages, circular economy hubs, and governance initiatives worldwide</li><li><strong>Web3 Funding</strong> — Quadratic funding, DAOs, and Collaborative Finance for local projects</li><li><strong>Open Resources</strong> — A global knowledge commons of governance models and production blueprints</li><li><strong>Education & Advocacy</strong> — Engaging policymakers to scale cosmolocal principles</li><li><strong>Pilots & Grants</strong> — Funding projects that demonstrate scalable solutions</li><li><strong>Cosmolocal Certification</strong> — Blockchain-verified standards for cosmolocal initiatives</li><li><strong>Global Alliances</strong> — Bioregional collaboration on governance and mutual aid</li><li><strong>Impact Research</strong> — Evidence-based scaling through the Cosmolocal Research Institute</li></ol><p>Want to learn more or get involved? Reply to this email — we'd love to hear from you.</p><p>Best,<br/>The Cosmolocal Foundation Team</p>\"\n}",
"fromEmail": "={{ $env.N8N_SMTP_SENDER }}",
"toEmail": "={{ $('Extract Contact Fields').item.json.email }}",
"subject": "Our Strategic Priorities — How We're Building Change",
"emailType": "html",
"html": "<h2>Hi {{ $('Extract Contact Fields').item.json.firstName }},</h2><p>We wanted to share more about our strategic approach to systemic transformation.</p><p>The Cosmolocal Foundation is executing on eight key initiatives:</p><ol><li><strong>Mapping Regenerative Communities</strong> — Cataloging eco-villages, circular economy hubs, and governance initiatives worldwide</li><li><strong>Web3 Funding</strong> — Quadratic funding, DAOs, and Collaborative Finance for local projects</li><li><strong>Open Resources</strong> — A global knowledge commons of governance models and production blueprints</li><li><strong>Education & Advocacy</strong> — Engaging policymakers to scale cosmolocal principles</li><li><strong>Pilots & Grants</strong> — Funding projects that demonstrate scalable solutions</li><li><strong>Cosmolocal Certification</strong> — Blockchain-verified standards for cosmolocal initiatives</li><li><strong>Global Alliances</strong> — Bioregional collaboration on governance and mutual aid</li><li><strong>Impact Research</strong> — Evidence-based scaling through the Cosmolocal Research Institute</li></ol><p>Want to learn more or get involved? Reply to this email — we'd love to hear from you.</p><p>Best,<br/>The Cosmolocal Foundation Team</p>",
"options": {}
},
"id": "send-followup-email",
"name": "Send Follow-up Email (Day 3)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1120, 300]
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [1120, 300],
"credentials": {
"smtp": {
"id": "mailcow-smtp",
"name": "Mailcow SMTP"
}
}
},
{
"parameters": {
@ -126,31 +112,24 @@
},
{
"parameters": {
"method": "POST",
"url": "https://api.resend.com/emails",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{ $env.RESEND_API_KEY }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"from\": \"Cosmolocal Foundation <***REDACTED_EMAIL***>\",\n \"to\": [\"{{ $('Extract Contact Fields').item.json.email }}\"],\n \"subject\": \"Join the Movement — Ways to Participate\",\n \"html\": \"<h2>Hi {{ $('Extract Contact Fields').item.json.firstName }},</h2><p>We believe in the power of collaboration. Here are ways you can participate in the cosmolocal movement:</p><ul><li><strong>Subscribe to our newsletter</strong> — Stay updated on projects, pilots, and governance experiments</li><li><strong>Join a working group</strong> — Contribute your expertise to research, technology, or community building</li><li><strong>Support a pilot project</strong> — Help fund or participate in cosmolocal demonstrations</li><li><strong>Spread the word</strong> — Share our vision with your network</li></ul><p>Visit <a href='https://cosmolocal.world'>cosmolocal.world</a> to explore our work, or simply reply to this email to start a conversation.</p><p>Together we can build regenerative economies that serve communities and the planet.</p><p>In solidarity,<br/>The Cosmolocal Foundation Team</p>\"\n}",
"fromEmail": "={{ $env.N8N_SMTP_SENDER }}",
"toEmail": "={{ $('Extract Contact Fields').item.json.email }}",
"subject": "Join the Movement — Ways to Participate",
"emailType": "html",
"html": "<h2>Hi {{ $('Extract Contact Fields').item.json.firstName }},</h2><p>We believe in the power of collaboration. Here are ways you can participate in the cosmolocal movement:</p><ul><li><strong>Subscribe to our newsletter</strong> — Stay updated on projects, pilots, and governance experiments</li><li><strong>Join a working group</strong> — Contribute your expertise to research, technology, or community building</li><li><strong>Support a pilot project</strong> — Help fund or participate in cosmolocal demonstrations</li><li><strong>Spread the word</strong> — Share our vision with your network</li></ul><p>Visit <a href='https://cosmolocal.world'>cosmolocal.world</a> to explore our work, or simply reply to this email to start a conversation.</p><p>Together we can build regenerative economies that serve communities and the planet.</p><p>In solidarity,<br/>The Cosmolocal Foundation Team</p>",
"options": {}
},
"id": "send-engagement-email",
"name": "Send Engagement Email (Day 10)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1560, 300]
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [1560, 300],
"credentials": {
"smtp": {
"id": "mailcow-smtp",
"name": "Mailcow SMTP"
}
}
},
{
"parameters": {

View File

@ -101,7 +101,7 @@
},
{
"parameters": {
"jsCode": "const items = $input.all();\nconst contactList = items.map(item => \n `- **${item.json.fullName}** (${item.json.email}) — ${item.json.daysSinceUpdate} days since last update`\n).join('\\n');\n\nconst count = items.length;\n\nreturn [{\n json: {\n subject: `[Cosmolocal CRM] ${count} contact${count !== 1 ? 's' : ''} need${count === 1 ? 's' : ''} follow-up`,\n htmlBody: `<h2>Stale Contact Report</h2><p>The following ${count} contact${count !== 1 ? 's have' : ' has'} not been updated in 14+ days:</p><table style=\"border-collapse:collapse;width:100%\"><tr style=\"background:#f5f5f4\"><th style=\"padding:8px;text-align:left;border:1px solid #e7e5e4\">Name</th><th style=\"padding:8px;text-align:left;border:1px solid #e7e5e4\">Email</th><th style=\"padding:8px;text-align:left;border:1px solid #e7e5e4\">Days Stale</th></tr>${items.map(i => `<tr><td style=\"padding:8px;border:1px solid #e7e5e4\">${i.json.fullName}</td><td style=\"padding:8px;border:1px solid #e7e5e4\">${i.json.email}</td><td style=\"padding:8px;border:1px solid #e7e5e4\">${i.json.daysSinceUpdate}</td></tr>`).join('')}</table><p style=\"margin-top:16px\"><a href=\"https://crm.cosmolocal.world\">Open CRM</a> to follow up.</p><p style=\"color:#78716c;font-size:12px\">Automated by n8n — automate.cosmolocal.world</p>`,\n count\n }\n}];"
"jsCode": "const items = $input.all();\nconst count = items.length;\n\nconst tableRows = items.map(i => `<tr><td style=\"padding:8px;border:1px solid #e7e5e4\">${i.json.fullName}</td><td style=\"padding:8px;border:1px solid #e7e5e4\">${i.json.email}</td><td style=\"padding:8px;border:1px solid #e7e5e4\">${i.json.daysSinceUpdate}</td></tr>`).join('');\n\nreturn [{\n json: {\n subject: `[Cosmolocal CRM] ${count} contact${count !== 1 ? 's' : ''} need${count === 1 ? 's' : ''} follow-up`,\n htmlBody: `<h2>Stale Contact Report</h2><p>The following ${count} contact${count !== 1 ? 's have' : ' has'} not been updated in 14+ days:</p><table style=\"border-collapse:collapse;width:100%\"><tr style=\"background:#f5f5f4\"><th style=\"padding:8px;text-align:left;border:1px solid #e7e5e4\">Name</th><th style=\"padding:8px;text-align:left;border:1px solid #e7e5e4\">Email</th><th style=\"padding:8px;text-align:left;border:1px solid #e7e5e4\">Days Stale</th></tr>${tableRows}</table><p style=\"margin-top:16px\"><a href=\"https://crm.cosmolocal.world\">Open CRM</a> to follow up.</p><p style=\"color:#78716c;font-size:12px\">Automated by n8n — automate.cosmolocal.world</p>`,\n count\n }\n}];"
},
"id": "build-report",
"name": "Build Report Email",
@ -111,31 +111,24 @@
},
{
"parameters": {
"method": "POST",
"url": "https://api.resend.com/emails",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer {{ $env.RESEND_API_KEY }}"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"from\": \"CRM Bot <automate@cosmolocal.world>\",\n \"to\": [\"***REDACTED_EMAIL***\"],\n \"subject\": \"{{ $json.subject }}\",\n \"html\": \"{{ $json.htmlBody }}\"\n}",
"fromEmail": "={{ $env.N8N_SMTP_SENDER }}",
"toEmail": "***REDACTED_EMAIL***",
"subject": "={{ $json.subject }}",
"emailType": "html",
"html": "={{ $json.htmlBody }}",
"options": {}
},
"id": "send-reminder-email",
"name": "Send Reminder to Team",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1560, 240]
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [1560, 240],
"credentials": {
"smtp": {
"id": "mailcow-smtp",
"name": "Mailcow SMTP"
}
}
},
{
"parameters": {},

View File

@ -9,9 +9,12 @@ API keys are passed as **Docker environment variables** in `docker-compose.yml`
| Variable | Description | Where to find |
|----------|-------------|---------------|
| `TWENTY_API_KEY` | Twenty CRM API key | crm.cosmolocal.world > Settings > API Keys |
| `RESEND_API_KEY` | Resend email API key | `ssh netcup "cat ~/.resend_credentials"` |
| `SMTP_USER` | Mailcow SMTP username | e.g. `***REDACTED_EMAIL***` |
| `SMTP_PASS` | Mailcow SMTP password | Mailcow admin panel at ***REDACTED_SMTP_HOST*** |
| `LISTMONK_CREDENTIALS` | Listmonk `user:pass` | Internal Docker service credentials |
Email is sent via **Mailcow SMTP** (`***REDACTED_SMTP_HOST***:587` STARTTLS). After importing workflows, create an SMTP credential in n8n named "Mailcow SMTP" with the host/user/pass above.
To set keys, create `/opt/websites/cosmolocal-website/.env` on the server and redeploy.
## Workflows