# Sendy + n8n Integration Guide for Rust Meetup 2025\n\n## Overview\n\nComplete integration guide for connecting Sendy (self-hosted email marketing) with your event management stack using n8n for workflow automation on Kubernetes.\n\n## Architecture Overview\n\n```plaintext\nEvent Registration Flow:\nQR Code/Landing Page → Typebot → n8n → Sendy + Baserow + Formbricks\n ↓\nLive Event Polls → Claper → n8n → Sendy Segments + Analytics\n ↓\nPost-Event Follow-up → Automated Email Sequences + Survey Distribution\n```\n\n## Sendy API Integration\n\n### Authentication & Setup\n\n```bash\n# Sendy API Configuration\nSENDY_API_KEY="your-api-key"\nSENDY_INSTALLATION_URL="https://sendy.yourdomain.com"\nSENDY_LIST_ID="your-list-id"\n```\n\n### Key API Endpoints\n\n```javascript\n// Subscribe endpoint\nPOST /api/subscribe.php\n{\n "api_key": "your-api-key",\n "email": "attendee@example.com",\n "list": "list-id",\n "name": "Attendee Name",\n "custom_fields": {\n "registration_source": "rust-meetup-2025",\n "interest_level": "high",\n "experience": "intermediate"\n }\n}\n\n// Unsubscribe endpoint\nPOST /api/unsubscribe.php\n\n// Get subscriber status\nPOST /api/subscriber-status.php\n\n// Create campaign\nPOST /api/create-send.php\n```\n\n## n8n Kubernetes Deployment\n\n### Namespace and ConfigMap\n\n```yaml\n# n8n-namespace.yaml\napiVersion: v1\nkind: Namespace\nmetadata:\n name: n8n-automation\n labels:\n name: n8n-automation\n app: event-automation\n\n---\n# n8n-config.yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n name: n8n-config\n namespace: n8n-automation\ndata:\n N8N_BASIC_AUTH_ACTIVE: "true"\n N8N_BASIC_AUTH_USER: "admin"\n N8N_HOST: "n8n.rust-meetup.local"\n N8N_PORT: "5678"\n N8N_PROTOCOL: "https"\n WEBHOOK_URL: "https://n8n.rust-meetup.local"\n GENERIC_TIMEZONE: "Europe/Madrid"\n N8N_METRICS: "true"\n N8N_LOG_LEVEL: "info"\n N8N_EDITOR_BASE_URL: "https://n8n.rust-meetup.local"\n N8N_DISABLE_UI: "false"\n N8N_PERSONALIZATION_ENABLED: "false"\n N8N_VERSION_NOTIFICATIONS_ENABLED: "false"\n N8N_DIAGNOSTICS_ENABLED: "false"\n N8N_PUBLIC_API_DISABLED: "false"\n EXECUTIONS_PROCESS: "main"\n EXECUTIONS_MODE: "regular"\n QUEUE_BULL_REDIS_HOST: "redis-cluster"\n QUEUE_BULL_REDIS_PORT: "6379"\n DB_TYPE: "postgresdb"\n DB_POSTGRESDB_HOST: "postgresql-ha-primary"\n DB_POSTGRESDB_PORT: "5432"\n DB_POSTGRESDB_DATABASE: "n8n"\n DB_POSTGRESDB_USER: "n8n"\n```\n\n### Secrets\n\n```yaml\n# n8n-secrets.yaml\napiVersion: v1\nkind: Secret\nmetadata:\n name: n8n-secrets\n namespace: n8n-automation\ntype: Opaque\nstringData:\n N8N_BASIC_AUTH_PASSWORD: "secure-password-here"\n DB_POSTGRESDB_PASSWORD: "postgres-password"\n ENCRYPTION_KEY: "your-encryption-key-32-chars-long"\n # Sendy Configuration\n SENDY_API_KEY: "your-sendy-api-key"\n SENDY_INSTALLATION_URL: "https://sendy.yourdomain.com"\n SENDY_LIST_ID: "rust-meetup-list-id"\n # Integration Keys\n TYPEBOT_API_KEY: "your-typebot-api-key"\n FORMBRICKS_API_KEY: "your-formbricks-api-key"\n BASEROW_API_KEY: "your-baserow-api-key"\n CLAPER_WEBHOOK_SECRET: "claper-webhook-secret"\n```\n\n### PersistentVolumeClaim\n\n```yaml\n# n8n-storage.yaml\napiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n name: n8n-data\n namespace: n8n-automation\nspec:\n accessModes:\n - ReadWriteOnce\n resources:\n requests:\n storage: 10Gi\n storageClassName: fast-ssd\n```\n\n### Deployment\n\n```yaml\n# n8n-deployment.yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: n8n\n namespace: n8n-automation\n labels:\n app: n8n\n version: v1\nspec:\n replicas: 1\n selector:\n matchLabels:\n app: n8n\n version: v1\n template:\n metadata:\n labels:\n app: n8n\n version: v1\n spec:\n containers:\n - name: n8n\n image: n8nio/n8n:1.57.0\n ports:\n - containerPort: 5678\n name: http\n envFrom:\n - configMapRef:\n name: n8n-config\n - secretRef:\n name: n8n-secrets\n volumeMounts:\n - name: n8n-data\n mountPath: /home/node/.n8n\n resources:\n requests:\n memory: "512Mi"\n cpu: "250m"\n limits:\n memory: "2Gi"\n cpu: "1000m"\n livenessProbe:\n httpGet:\n path: /healthz\n port: 5678\n initialDelaySeconds: 60\n periodSeconds: 30\n readinessProbe:\n httpGet:\n path: /healthz\n port: 5678\n initialDelaySeconds: 30\n periodSeconds: 10\n securityContext:\n runAsNonRoot: true\n runAsUser: 1000\n allowPrivilegeEscalation: false\n readOnlyRootFilesystem: false\n volumes:\n - name: n8n-data\n persistentVolumeClaim:\n claimName: n8n-data\n securityContext:\n fsGroup: 1000\n```\n\n### Service\n\n```yaml\n# n8n-service.yaml\napiVersion: v1\nkind: Service\nmetadata:\n name: n8n\n namespace: n8n-automation\n labels:\n app: n8n\nspec:\n selector:\n app: n8n\n ports:\n - name: http\n port: 80\n targetPort: 5678\n protocol: TCP\n type: ClusterIP\n```\n\n### Ingress (Traditional)\n\n```yaml\n# n8n-ingress.yaml\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n name: n8n-ingress\n namespace: n8n-automation\n annotations:\n kubernetes.io/ingress.class: "nginx"\n nginx.ingress.kubernetes.io/ssl-redirect: "true"\n nginx.ingress.kubernetes.io/force-ssl-redirect: "true"\n nginx.ingress.kubernetes.io/proxy-body-size: "50m"\n nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"\n nginx.ingress.kubernetes.io/proxy-send-timeout: "300"\n nginx.ingress.kubernetes.io/proxy-read-timeout: "300"\n cert-manager.io/cluster-issuer: "letsencrypt-prod"\nspec:\n tls:\n - hosts:\n - n8n.rust-meetup.local\n secretName: n8n-tls\n rules:\n - host: n8n.rust-meetup.local\n http:\n paths:\n - path: /\n pathType: Prefix\n backend:\n service:\n name: n8n\n port:\n number: 80\n```\n\n### Istio VirtualService\n\n```yaml\n# n8n-virtualservice.yaml\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n name: n8n-vs\n namespace: n8n-automation\nspec:\n hosts:\n - n8n.rust-meetup.local\n gateways:\n - rust-meetup-gateway\n http:\n - match:\n - uri:\n prefix: /\n route:\n - destination:\n host: n8n.n8n-automation.svc.cluster.local\n port:\n number: 80\n timeout: 300s\n headers:\n request:\n add:\n X-Forwarded-Proto: "https"\n X-Forwarded-For: "%DOWNSTREAM_REMOTE_ADDRESS%"\n\n---\napiVersion: networking.istio.io/v1beta1\nkind: DestinationRule\nmetadata:\n name: n8n-dr\n namespace: n8n-automation\nspec:\n host: n8n.n8n-automation.svc.cluster.local\n trafficPolicy:\n connectionPool:\n tcp:\n maxConnections: 50\n http:\n http1MaxPendingRequests: 100\n maxRequestsPerConnection: 10\n outlierDetection:\n consecutiveErrors: 3\n interval: 30s\n baseEjectionTime: 30s\n```\n\n## n8n Workflow Templates\n\n### 1. Event Registration Workflow\n\n```json\n{\n "name": "Rust Meetup Registration Flow",\n "nodes": [\n {\n "parameters": {\n "httpMethod": "POST",\n "path": "registration",\n "responseMode": "responseNode"\n },\n "id": "webhook-registration",\n "name": "Registration Webhook",\n "type": "n8n-nodes-base.webhook",\n "position": [240, 300]\n },\n {\n "parameters": {\n "url": "={{ $env.SENDY_INSTALLATION_URL }}/api/subscribe.php",\n "sendHeaders": true,\n "headerParameters": {\n "parameters": [\n {\n "name": "Content-Type",\n "value": "application/x-www-form-urlencoded"\n }\n ]\n },\n "sendBody": true,\n "bodyParameters": {\n "parameters": [\n {\n "name": "api_key",\n "value": "={{ $env.SENDY_API_KEY }}"\n },\n {\n "name": "email",\n "value": "={{ $json.email }}"\n },\n {\n "name": "list",\n "value": "={{ $env.SENDY_LIST_ID }}"\n },\n {\n "name": "name",\n "value": "={{ $json.name }}"\n },\n {\n "name": "custom_fields",\n "value": "{{ JSON.stringify({ registration_source: 'rust-meetup-2025', interest_level: $json.interest_level, experience: $json.experience, registration_date: new Date().toISOString() }) }}"\n }\n ]\n }\n },\n "id": "sendy-subscribe",\n "name": "Add to Sendy List",\n "type": "n8n-nodes-base.httpRequest",\n "position": [460, 300]\n },\n {\n "parameters": {\n "url": "={{ $env.BASEROW_API_URL }}/api/database/rows/table/{{ $env.BASEROW_ATTENDEES_TABLE_ID }}/",\n "sendHeaders": true,\n "headerParameters": {\n "parameters": [\n {\n "name": "Authorization",\n "value": "Token {{ $env.BASEROW_API_KEY }}"\n }\n ]\n },\n "sendBody": true,\n "bodyParameters": {\n "parameters": [\n {\n "name": "name",\n "value": "={{ $json.name }}"\n },\n {\n "name": "email",\n "value": "={{ $json.email }}"\n },\n {\n "name": "registration_source",\n "value": "typebot"\n },\n {\n "name": "registration_date",\n "value": "={{ new Date().toISOString() }}"\n },\n {\n "name": "status",\n "value": "registered"\n }\n ]\n }\n },\n "id": "baserow-create",\n "name": "Save to Baserow",\n "type": "n8n-nodes-base.httpRequest",\n "position": [680, 300]\n }\n ],\n "connections": {\n "Registration Webhook": {\n "main": [\n [\n {\n "node": "Add to Sendy List",\n "type": "main",\n "index": 0\n }\n ]\n ]\n },\n "Add to Sendy List": {\n "main": [\n [\n {\n "node": "Save to Baserow",\n "type": "main",\n "index": 0\n }\n ]\n ]\n }\n }\n}\n```\n\n### 2. Pre-Event Email Sequence\n\n```json\n{\n "name": "Pre-Event Email Automation",\n "nodes": [\n {\n "parameters": {\n "rule": {\n "interval": [\n {\n "field": "cronExpression",\n "value": "0 9 * * *"\n }\n ]\n }\n },\n "id": "daily-trigger",\n "name": "Daily Check Trigger",\n "type": "n8n-nodes-base.cron",\n "position": [240, 300]\n },\n {\n "parameters": {\n "url": "={{ $env.SENDY_INSTALLATION_URL }}/api/create-send.php",\n "sendBody": true,\n "bodyParameters": {\n "parameters": [\n {\n "name": "api_key",\n "value": "={{ $env.SENDY_API_KEY }}"\n },\n {\n "name": "from_name",\n "value": "Rust Meetup Team"\n },\n {\n "name": "from_email",\n "value": "hello@rust-meetup.com"\n },\n {\n "name": "reply_to",\n "value": "hello@rust-meetup.com"\n },\n {\n "name": "subject",\n "value": "¡Solo quedan {{ $json.days_remaining }} días para el Rust Meetup!"\n },\n {\n "name": "html_text",\n "value": "{{ $json.email_template }}"\n },\n {\n "name": "list_ids",\n "value": "={{ $env.SENDY_LIST_ID }}"\n },\n {\n "name": "send_campaign",\n "value": "1"\n }\n ]\n }\n },\n "id": "send-reminder",\n "name": "Send Reminder Email",\n "type": "n8n-nodes-base.httpRequest",\n "position": [680, 300]\n }\n ]\n}\n```\n\n### 3. Live Event Integration\n\n```json\n{\n "name": "Live Event Poll Integration",\n "nodes": [\n {\n "parameters": {\n "httpMethod": "POST",\n "path": "poll-response",\n "responseMode": "responseNode"\n },\n "id": "poll-webhook",\n "name": "Poll Response Webhook",\n "type": "n8n-nodes-base.webhook",\n "position": [240, 300]\n },\n {\n "parameters": {\n "url": "={{ $env.BASEROW_API_URL }}/api/database/rows/table/{{ $env.BASEROW_LIVE_ENGAGEMENT_TABLE_ID }}/",\n "sendHeaders": true,\n "headerParameters": {\n "parameters": [\n {\n "name": "Authorization",\n "value": "Token {{ $env.BASEROW_API_KEY }}"\n }\n ]\n },\n "sendBody": true,\n "bodyParameters": {\n "parameters": [\n {\n "name": "attendee_email",\n "value": "={{ $json.email }}"\n },\n {\n "name": "poll_question",\n "value": "={{ $json.question }}"\n },\n {\n "name": "response",\n "value": "={{ $json.answer }}"\n },\n {\n "name": "timestamp",\n "value": "={{ new Date().toISOString() }}"\n },\n {\n "name": "engagement_score",\n "value": "={{ $json.engagement_points || 10 }}"\n }\n ]\n }\n },\n "id": "save-engagement",\n "name": "Save Engagement Data",\n "type": "n8n-nodes-base.httpRequest",\n "position": [460, 300]\n },\n {\n "parameters": {\n "conditions": {\n "string": [\n {\n "value1": "={{ $json.engagement_score }}",\n "operation": "largerEqual",\n "value2": "50"\n }\n ]\n }\n },\n "id": "check-engagement",\n "name": "High Engagement?",\n "type": "n8n-nodes-base.if",\n "position": [680, 300]\n },\n {\n "parameters": {\n "url": "={{ $env.SENDY_INSTALLATION_URL }}/api/subscribe.php",\n "sendBody": true,\n "bodyParameters": {\n "parameters": [\n {\n "name": "api_key",\n "value": "={{ $env.SENDY_API_KEY }}"\n },\n {\n "name": "email",\n "value": "={{ $json.email }}"\n },\n {\n "name": "list",\n "value": "={{ $env.SENDY_HIGH_ENGAGEMENT_LIST_ID }}"\n },\n {\n "name": "custom_fields",\n "value": "{{ JSON.stringify({ segment: 'high_engagement', last_interaction: new Date().toISOString() }) }}"\n }\n ]\n }\n },\n "id": "segment-high-engagement",\n "name": "Add to High Engagement Segment",\n "type": "n8n-nodes-base.httpRequest",\n "position": [900, 200]\n }\n ]\n}\n```\n\n## QR Code Integration Strategy\n\n### 1. Dynamic QR Code Generation\n\n```javascript\n// QR Code Generation Service\nconst QRCode = require('qrcode');\n\nasync function generateEventQR(attendeeEmail, source = 'general') {\n const registrationUrl = `https://typebot.rust-meetup.local/rust-meetup-registration?email=${encodeURIComponent(attendeeEmail)}&source=${source}&utm_campaign=rust-meetup-2025`;\n\n const qrOptions = {\n errorCorrectionLevel: 'M',\n type: 'image/png',\n quality: 0.92,\n margin: 1,\n color: {\n dark: '#000000',\n light: '#FFFFFF',\n },\n width: 256\n };\n\n return await QRCode.toDataURL(registrationUrl, qrOptions);\n}\n```\n\n### 2. Landing Page Integration\n\n```html\n\n\n\n\n \n \n Rust Meetup 2025 - Registro\n \n \n\n \n \n \n \n \n\n \n\n\n
\n \n\n
\n
\n 📅\n Fecha: 15 de Marzo, 2025\n
\n
\n 🕕\n Hora: 18:00 - 21:00 CET\n
\n
\n 📍\n Lugar: Tech Hub Madrid\n
\n
\n 👥\n Capacidad: 100 asistentes\n
\n
\n\n \n \n \n
\n\n \n \n\n\n```\n\n## Email Template System\n\n### Welcome Email Template\n\n```html\n\n\n\n \n \n ¡Bienvenido al Rust Meetup 2025!\n\n\n \n \n \n \n
\n \n \n \n \n \n\n \n \n \n \n\n \n \n \n \n
\n Rust Logo\n

¡Registro Confirmado!

\n

Rust Meetup 2025

\n
\n

Hola [name],

\n\n

\n ¡Gracias por registrarte en el Rust Meetup 2025! Estamos emocionados de tenerte con nosotros para explorar Infrastructure Automation with Rust, Nushell & KCL.\n

\n\n
\n

📅 Detalles del Evento

\n

Fecha: 15 de Marzo, 2025

\n

Hora: 18:00 - 21:00 CET

\n

Lugar: Tech Hub Madrid

\n

Dirección: Calle Innovation 42, Madrid

\n
\n\n
\n

🎯 Lo que aprenderás:

\n
    \n
  • Automatización de infraestructura con Rust
  • \n
  • Uso avanzado de Nushell para DevOps
  • \n
  • Configuración declarativa con KCL
  • \n
  • Mejores prácticas de Cloud Native
  • \n
\n
\n\n \n\n
\n

📋 Antes del evento:

\n

\n Te enviaremos un cuestionario previo para personalizar mejor la experiencia.\n ¡Mantente atento a tu email!\n

\n
\n\n

\n Si tienes alguna pregunta, no dudes en responder este email.\n

\n\n

\n ¡Nos vemos pronto!
\n El equipo de Rust Meetup\n

\n
\n

\n Síguenos en redes sociales:\n

\n Twitter\n GitHub\n LinkedIn\n\n

\n Rust Meetup Madrid | Tech Hub Madrid
\n Calle Innovation 42, 28001 Madrid\n

\n\n \n Darse de baja\n \n
\n
\n\n\n```\n\n## Integration Monitoring\n\n### Prometheus Metrics\n\n```yaml\n# n8n-monitoring.yaml\napiVersion: v1\nkind: ServiceMonitor\nmetadata:\n name: n8n-metrics\n namespace: n8n-automation\n labels:\n app: n8n\nspec:\n selector:\n matchLabels:\n app: n8n\n endpoints:\n - port: http\n path: /metrics\n interval: 30s\n```\n\n### Grafana Dashboard\n\n```json\n{\n "dashboard": {\n "title": "Rust Meetup - n8n & Sendy Integration",\n "panels": [\n {\n "title": "Registration Rate",\n "type": "stat",\n "targets": [\n {\n "expr": "rate(n8n_workflow_executions_total{workflow_name=\"Rust Meetup Registration Flow\"}[5m])",\n "legendFormat": "Registrations/min"\n }\n ]\n },\n {\n "title": "Email Delivery Success Rate",\n "type": "stat",\n "targets": [\n {\n "expr": "rate(n8n_workflow_executions_total{workflow_name=\"Pre-Event Email Automation\",status=\"success\"}[1h]) / rate(n8n_workflow_executions_total{workflow_name=\"Pre-Event Email Automation\"}[1h])",\n "legendFormat": "Success Rate %"\n }\n ]\n },\n {\n "title": "Live Engagement Score",\n "type": "graph",\n "targets": [\n {\n "expr": "avg(baserow_engagement_score) by (poll_question)",\n "legendFormat": "{{ poll_question }}"\n }\n ]\n }\n ]\n }\n}\n```\n\n## Best Practices\n\n### 1. Registration Flow Optimization\n\n- **Multiple Entry Points**: QR codes, direct URLs, social media links\n- **Progressive Profiling**: Collect minimal info initially, expand during event\n- **A/B Testing**: Test different landing page versions\n- **Mobile First**: Ensure perfect mobile experience\n\n### 2. Segmentation Strategy\n\n```javascript\n// Sendy Custom Fields for Segmentation\nconst segmentationFields = {\n experience_level: ['beginner', 'intermediate', 'advanced'],\n interest_areas: ['infrastructure', 'automation', 'rust', 'devops'],\n company_size: ['startup', 'small', 'medium', 'enterprise'],\n role: ['developer', 'devops', 'architect', 'manager'],\n previous_attendee: ['yes', 'no'],\n engagement_score: 'numeric',\n last_interaction: 'datetime'\n};\n```\n\n### 3. Email Automation Sequences\n\n```plaintext\nPre-Event Sequence:\nDay -7: Welcome + Event Details + Calendar Invite\nDay -3: Pre-event Survey + Preparation Materials\nDay -1: Final Reminder + Access Instructions\nDay 0: Event Day - Location & Last-minute Updates\n\nPost-Event Sequence:\nDay +1: Thank You + Survey + Resources\nDay +3: Presentation Slides + Additional Resources\nDay +7: Community Follow-up + Next Events\nDay +30: Long-term Engagement Survey\n```\n\n### 4. Security Considerations\n\n```yaml\n# Security Headers for n8n\nannotations:\n nginx.ingress.kubernetes.io/configuration-snippet: |\n add_header X-Frame-Options "SAMEORIGIN" always;\n add_header X-Content-Type-Options "nosniff" always;\n add_header X-XSS-Protection "1; mode=block" always;\n add_header Referrer-Policy "strict-origin-when-cross-origin" always;\n add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;\n```\n\n## Deployment Commands\n\n```bash\n# Deploy n8n\nkubectl apply -f n8n-namespace.yaml\nkubectl apply -f n8n-secrets.yaml\nkubectl apply -f n8n-config.yaml\nkubectl apply -f n8n-storage.yaml\nkubectl apply -f n8n-deployment.yaml\nkubectl apply -f n8n-service.yaml\nkubectl apply -f n8n-ingress.yaml\nkubectl apply -f n8n-virtualservice.yaml\n\n# Verify deployment\nkubectl get pods -n n8n-automation\nkubectl logs -f deployment/n8n -n n8n-automation\n\n# Access n8n\nkubectl port-forward svc/n8n 8080:80 -n n8n-automation\n# Then access: http://localhost:8080\n```\n\nThis complete setup provides a robust, scalable integration between Sendy and your event management tools using n8n on Kubernetes with both traditional Ingress and Istio support.