diff --git a/apps/wiki/content/docs/guides/meta.json b/apps/wiki/content/docs/guides/meta.json index a2290cf..4a59a62 100644 --- a/apps/wiki/content/docs/guides/meta.json +++ b/apps/wiki/content/docs/guides/meta.json @@ -1,3 +1,3 @@ { - "pages": ["list-hygiene", "verifying-domains", "tracking", "api-keys", "localization", "webhooks"] + "pages": ["list-hygiene", "verifying-domains", "receiving-emails", "tracking", "api-keys", "localization", "webhooks"] } diff --git a/apps/wiki/content/docs/guides/receiving-emails.mdx b/apps/wiki/content/docs/guides/receiving-emails.mdx new file mode 100644 index 0000000..64d5687 --- /dev/null +++ b/apps/wiki/content/docs/guides/receiving-emails.mdx @@ -0,0 +1,142 @@ +--- +title: Receiving emails +description: Receive incoming emails at your verified domain and trigger automated workflows +icon: Inbox +--- + +Plunk can receive emails sent to your verified domain and turn them into `email.received` events. This allows you to build automated workflows that respond to inbound emails, such as support ticket systems, auto-responders, or email-based integrations. + +## How it works + +When someone sends an email to your verified domain (e.g., `support@yourdomain.com` or `hello@yourdomain.com`), Plunk will: + +1. Receive the email through AWS SES +2. Automatically create or update a contact for the sender +3. Trigger an `email.received` event that can start workflows +4. Make the email metadata available to your workflow steps + +The sender is automatically added to your contacts as a subscribed contact, allowing you to respond using Plunk's email sending capabilities. + +## Setting up inbound email + +
+ +### Verify your domain + +Before you can receive emails, your domain must be verified in Plunk. Follow the [verifying domains](/guides/verifying-domains) guide to set up the required DKIM, SPF, and MX records for sending. + +### Add the inbound MX record + +In your project settings, navigate to the **Domains** tab and expand your verified domain. You'll see an optional "Inbound Email" section with an MX record configuration: + +- **Type**: MX +- **Name**: `yourdomain.com` (your root domain) +- **Value**: `10 inbound-smtp.eu-north-1.amazonaws.com` + +Add this MX record to your domain's DNS settings. The priority value `10` ensures that inbound emails are routed to AWS SES for processing. + + + If you're already using MX records for another email service (like Google Workspace or Microsoft 365), adding this MX + record may conflict. You can only have one primary email receiver per domain. Consider using a subdomain (e.g., + `mail.yourdomain.com`) if you need to maintain both services. + + +### Wait for DNS propagation + +DNS changes can take anywhere from a few minutes to 48 hours to fully propagate. You can verify the MX record is set correctly using: + +```bash +dig MX yourdomain.com +``` + +You should see the AWS SES inbound endpoint in the response. + +
+ +## Creating workflows with email.received + +Once your MX record is configured, you can create workflows that respond to incoming emails. + +### Event trigger + +Create a new workflow and use `email.received` as the trigger event. This workflow will run every time an email is received at your domain. + +### Available event data + +The `email.received` event includes the following data that you can use in your workflow steps: + +| Field | Type | Description | +| ---------------------- | -------- | ---------------------------------------------- | +| `messageId` | string | Unique identifier for the received message | +| `from` | string | Email address of the sender | +| `fromHeader` | string | Full "From" header including display name | +| `to` | string | Primary recipient email address | +| `subject` | string | Email subject line | +| `timestamp` | string | ISO 8601 timestamp when the email was received | +| `recipients` | string[] | All recipient email addresses | +| `hasContent` | boolean | Whether the email body was captured | +| `spamVerdict` | string | Spam check result (e.g., "PASS", "FAIL") | +| `virusVerdict` | string | Virus scan result (e.g., "PASS", "FAIL") | +| `spfVerdict` | string | SPF authentication result | +| `dkimVerdict` | string | DKIM authentication result | +| `dmarcVerdict` | string | DMARC authentication result | +| `processingTimeMillis` | number | Time taken to process the email | + +You can access these fields in your workflow using variable syntax, for example: `{{event.subject}}` or `{{event.from}}`. + +## Multi-project domains + +If you have verified the same domain in multiple projects, incoming emails will be processed for **all projects** that have the domain verified. Each project will: + +- Create/update the sender as a contact in that project +- Trigger the `email.received` event in that project +- Run any workflows configured for that event + +This allows you to segment inbound email handling across different projects if needed. + +## Limitations + + + Currently, the email body content is not stored or made available in the event data. Only metadata (sender, subject, + recipients, timestamps, and security verdicts) is captured. The `hasContent` field indicates whether body content was + present, but the content itself is not accessible in workflows. + + +- **Catch-all addresses**: Plunk receives emails sent to any address at your verified domain (e.g., `anything@yourdomain.com`). You can use workflow conditions to route emails based on the `to` field. +- **Attachments**: Email attachments are not currently captured or stored. +- **Email size**: AWS SES has a maximum message size limit of 40 MB for inbound emails. + +## Security considerations + +Plunk captures several security verdicts for each incoming email: + +- **SPF (Sender Policy Framework)**: Verifies the sender's mail server is authorized +- **DKIM (DomainKeys Identified Mail)**: Validates the email hasn't been tampered with +- **DMARC (Domain-based Message Authentication)**: Combines SPF and DKIM for additional validation +- **Spam verdict**: AWS SES's spam detection result +- **Virus verdict**: AWS SES's virus scanning result + +You can use these verdicts in workflow conditions to automatically filter or quarantine suspicious emails before processing them. + +## Troubleshooting + +### Emails not being received + +1. **Check DNS propagation**: Verify the MX record is correctly set using `dig MX yourdomain.com` +2. **Verify domain**: Ensure your domain is fully verified in Plunk (all DKIM, SPF, and MX records for sending) +3. **Check workflow**: Create a simple test workflow with just an `email.received` trigger and a webhook to verify events are being generated +4. **Check sender**: Try sending from a different email provider as some may cache DNS records + +### Duplicate events + +If you have the same domain verified in multiple projects, you will receive duplicate `email.received` events (one per project). This is expected behavior. Use project-specific workflows to handle this. + +### Security verdicts failing + +If incoming emails consistently show failing security verdicts: + +- **SPF failures**: The sender's domain may not have SPF configured correctly +- **DKIM failures**: The sender's domain may not have DKIM configured, or the email was forwarded/modified in transit +- **DMARC failures**: The sender fails both SPF and DKIM checks + +These are issues with the sender's configuration, not your Plunk setup. You can choose to process these emails anyway or filter them using workflow conditions. diff --git a/apps/wiki/content/docs/guides/verifying-domains.mdx b/apps/wiki/content/docs/guides/verifying-domains.mdx index 5addeee..7e78d6e 100644 --- a/apps/wiki/content/docs/guides/verifying-domains.mdx +++ b/apps/wiki/content/docs/guides/verifying-domains.mdx @@ -9,9 +9,78 @@ Verifying your domain is a requirement to send emails through Plunk. Domain veri ## Verifying a domain You can verify a domain by adding it in the domain tab of the project settings. Once added, Plunk will provide you with the necessary DNS records to add to your domain's DNS settings. + Once you have added the DNS records, it may take some time for the changes to propagate. You can check the verification status in the domain tab of the project settings. -### DNS Records -- 3 CNAME records for DKIM (DomainKeys Identified Mail) to authenticate your emails. -- 1 TXT record for SPF (Sender Policy Framework) to specify which mail servers are authorized -- 1 MX record to handle bounces and feedback loops +## DNS Records + +Domain verification requires adding several DNS records to your domain. Each record serves a specific purpose in email authentication and delivery. + +### DKIM Records (3 CNAME records) + +**DomainKeys Identified Mail (DKIM)** adds a digital signature to your emails, proving they haven't been tampered with during transit. + +You'll need to add **3 CNAME records** provided by Plunk. These records contain cryptographic keys that email receivers use to verify your emails are authentic. + +**Why it matters:** + +- Prevents email spoofing and tampering +- Improves deliverability and inbox placement +- Required by most email providers (Gmail, Outlook, etc.) + +### SPF Record (1 TXT record) + +**Sender Policy Framework (SPF)** specifies which mail servers are authorized to send emails on behalf of your domain. + +You'll need to add **1 TXT record** that lists the authorized sending servers. + +**Why it matters:** + +- Prevents unauthorized servers from sending emails using your domain +- Reduces the likelihood of your domain being used for spam +- Works together with DKIM for complete authentication + +### Bounce Handling (1 MX record) + +This **MX record** allows Plunk to receive bounce notifications and spam complaints from email providers. + +**Why it matters:** + +- Automatically tracks which contacts have bounced or complained +- Helps maintain your sender reputation +- Prevents sending to invalid email addresses +- Required for deliverability monitoring + + + The MX record above is for sending emails (handling bounces and complaints). If you want to **receive** emails at your + domain and trigger workflows, see the [receiving emails](/guides/receiving-emails) guide for additional MX record + setup. + + +## Verification Status + +After adding all DNS records, Plunk will automatically check the verification status. Verification typically completes within a few minutes but can take up to 72 hours depending on DNS propagation. + +You can check the status in the Domains section of your project settings. Each record type will show as verified once detected. + +## Troubleshooting + +### Records not verifying + +If your DNS records aren't verifying after 24 hours: + +1. **Double-check the values**: Ensure you copied the exact values without extra spaces +2. **Check DNS propagation**: Use tools like `dig` or online DNS checkers to verify the records are published +3. **TTL settings**: Some DNS providers cache records. Try lowering the TTL (Time To Live) value +4. **Contact your DNS provider**: Some providers have specific requirements or interfaces for adding these record types + +### Emails still going to spam + +Even with a verified domain, emails may go to spam if: + +- Your content triggers spam filters (excessive links, suspicious keywords) +- Your sender reputation is new or low +- Recipients have marked your emails as spam in the past +- You're sending to invalid or unengaged contacts + +Follow email best practices and maintain good [list hygiene](/guides/list-hygiene) to improve deliverability. diff --git a/apps/wiki/content/docs/guides/webhooks.mdx b/apps/wiki/content/docs/guides/webhooks.mdx index ef71c2a..90fb94f 100644 --- a/apps/wiki/content/docs/guides/webhooks.mdx +++ b/apps/wiki/content/docs/guides/webhooks.mdx @@ -22,33 +22,33 @@ Plunk automatically tracks a set of internal events that you can use as workflow ### Email events -| Event | Description | -|-------|-------------| -| `email.sent` | An email was successfully sent | -| `email.delivery` | An email was delivered to the recipient | -| `email.open` | A contact opened an email for the first time | -| `email.click` | A contact clicked a link in an email for the first time | -| `email.bounce` | An email bounced (hard or soft bounce) | -| `email.complaint` | A contact marked an email as spam | +| Event | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| `email.sent` | An email was successfully sent | +| `email.delivery` | An email was delivered to the recipient | +| `email.open` | A contact opened an email for the first time | +| `email.click` | A contact clicked a link in an email for the first time | +| `email.bounce` | An email bounced (hard or soft bounce) | +| `email.complaint` | A contact marked an email as spam | +| `email.received` | An email was received at your verified domain (requires [inbound email setup](/guides/receiving-emails)) | ### Contact events -| Event | Description | -|-------|-------------| -| `contact.subscribed` | A contact's subscription status changed to subscribed | +| Event | Description | +| ---------------------- | ------------------------------------------------------- | +| `contact.subscribed` | A contact's subscription status changed to subscribed | | `contact.unsubscribed` | A contact's subscription status changed to unsubscribed | ### Segment events -| Event | Description | -|-------|-------------| +| Event | Description | +| ---------------------- | --------------------------- | | `segment..entry` | A contact entered a segment | -| `segment..exit` | A contact exited a segment | +| `segment..exit` | A contact exited a segment | - -Segment events use a slugified version of the segment name. For example, a segment called "VIP Users" would produce the events `segment.vip-users.entry` and `segment.vip-users.exit`. + + Segment events use a slugified version of the segment name. For example, a segment called "VIP Users" would produce + the events `segment.vip-users.entry` and `segment.vip-users.exit`. ## Setting up a webhook @@ -115,14 +115,14 @@ The `event` field contains the data associated with the event that triggered the The `event` field varies depending on which event triggered the workflow: -| Event | Fields in `event` | -|-------|-------------------| -| `email.sent` | `subject`, `from`, `messageId`, `templateId`, `campaignId`, `sourceType` | -| `email.open` | `subject`, `from`, `openedAt`, `isFirstOpen` | -| `email.click` | `subject`, `from`, `clickedAt`, `clicks`, `isFirstClick` | -| `email.bounce` | `subject`, `from`, `bounceType`, `bouncedAt` | -| `email.complaint` | `subject`, `from`, `complainedAt` | -| Custom events | Whatever data you passed when tracking the event | +| Event | Fields in `event` | +| ----------------- | ------------------------------------------------------------------------ | +| `email.sent` | `subject`, `from`, `messageId`, `templateId`, `campaignId`, `sourceType` | +| `email.open` | `subject`, `from`, `openedAt`, `isFirstOpen` | +| `email.click` | `subject`, `from`, `clickedAt`, `clicks`, `isFirstClick` | +| `email.bounce` | `subject`, `from`, `bounceType`, `bouncedAt` | +| `email.complaint` | `subject`, `from`, `complainedAt` | +| Custom events | Whatever data you passed when tracking the event | ## Common use cases @@ -150,4 +150,4 @@ Since webhooks are part of the workflow system, you can combine them with other - Use a **Condition** step to only fire the webhook when certain criteria are met (e.g. only notify for contacts on a specific plan) - Use a **Wait for Event** step to wait for a follow-up event before sending the webhook (e.g. wait to see if a bounced contact re-subscribes) -- Use a **Delay** step to add a time buffer before the webhook fires \ No newline at end of file +- Use a **Delay** step to add a time buffer before the webhook fires