# DKIM Source: https://docs.sendkit.dev/academy/authentication/dkim Learn how DKIM digitally signs your emails to prove authenticity and prevent tampering. ## What is DKIM? DKIM (DomainKeys Identified Mail) is an email authentication protocol that adds a **digital signature** to every email you send. This signature lets the recipient's mail server verify two things: 1. The email actually came from the claimed domain 2. The email content wasn't modified in transit Think of it like a tamper-proof seal on a package. If anyone opens the package and changes the contents, the seal breaks. ## How DKIM works DKIM uses **public key cryptography**. There are two keys: * **Private key** — kept secret on SendKit's servers. Used to sign each email. * **Public key** — published in your DNS as a TXT record. Used by recipients to verify the signature. Here's what happens when you send an email: SendKit creates a hash of the email headers and body. The hash is encrypted with your domain's private key, and the encrypted hash (signature) is added to the email header. The recipient's mail server looks up the public key in your DNS at `sendkit._domainkey.yourdomain.com`. The server decrypts the signature using the public key and creates its own hash of the received email. If the hashes match — **DKIM pass**. If they don't — **DKIM fail** (the email was tampered with in transit). ## The DKIM signature header When DKIM signs an email, it adds a `DKIM-Signature` header. Here's what it looks like: ``` DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=acme.com; s=sendkit; h=from:to:subject:date:message-id; bh=abcdef123456...; b=xyz789... ``` | Field | Meaning | | ----- | ------------------------------------------------------------- | | `v` | Version (always `1`) | | `a` | Signing algorithm (`rsa-sha256` is standard) | | `c` | Canonicalization — how the email is normalized before hashing | | `d` | The signing domain (your domain) | | `s` | The selector — identifies which key to look up in DNS | | `h` | The headers that were signed | | `bh` | Hash of the email body | | `b` | The actual signature | ## DKIM with SendKit When you add a domain in SendKit, we generate a unique DKIM key pair for your domain. You publish the public key as a DNS record: | Field | Value | | --------- | ------------------------------------- | | **Type** | TXT | | **Name** | `sendkit._domainkey.yourdomain.com` | | **Value** | `v=DKIM1; k=rsa; p=` | | **TTL** | 3600 | The `sendkit` part is the **selector**. It tells receiving servers which public key to use when verifying the signature. A domain can have multiple selectors for different services. The public key is unique to your domain and generated by SendKit. Always copy it from the domain detail page — don't try to create your own. ## Selectors A selector is a label that points to a specific DKIM key. It's part of the DNS record name: ``` ._domainkey.yourdomain.com ``` Selectors allow you to have multiple DKIM keys for the same domain. For example: | Selector | Service | | ----------------------------- | ---------------- | | `sendkit._domainkey.acme.com` | SendKit | | `google._domainkey.acme.com` | Google Workspace | | `s1._domainkey.acme.com` | Marketing tool | Each service has its own key pair and selector. They don't interfere with each other. ## Key rotation DKIM keys should be rotated periodically to maintain security. If a private key is ever compromised, an attacker could sign emails that pass DKIM verification. Key rotation involves: 1. Generating a new key pair 2. Publishing the new public key in DNS (with a new selector or same selector) 3. Switching to the new private key for signing 4. Removing the old public key after a transition period SendKit handles key management for you. If key rotation is needed, we'll notify you with instructions to update your DNS record. ## Common DKIM issues | Problem | Cause | Fix | | -------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------- | | DKIM none | No DKIM signature found | Ensure the email is being sent through SendKit (not directly) | | DKIM fail | Signature doesn't match | Check that the DNS record value matches exactly what SendKit provided. Some DNS providers add extra characters | | DKIM permerror | Public key not found in DNS | Verify the TXT record exists at the correct name (`sendkit._domainkey.yourdomain.com`) | | DKIM temperror | DNS timeout | Usually transient. Check your DNS provider's status | ### DNS record formatting issues Some DNS providers have trouble with long TXT records. DKIM public keys are long strings, and some providers: * **Truncate the value** — make sure the full key is saved * **Add quotes incorrectly** — the value should not include extra quotes beyond what your provider requires * **Split into multiple strings** — some providers automatically split long TXT records. This is fine as long as the full value is preserved ## FAQ No. DKIM **signs** your emails — it proves authenticity and integrity. It does not encrypt the content. For encryption in transit, see [TLS](/academy/security/tls). Technically yes, but it's not recommended. Each domain should have its own key pair for better security and isolation. SendKit generates a unique key for each domain you add. You need to re-add the DKIM TXT record at your new DNS provider. The record name and value stay the same — just copy them from the SendKit domain detail page. # DNS Propagation Source: https://docs.sendkit.dev/academy/authentication/dns-propagation Understand how DNS propagation works and why domain verification can take time. ## What is DNS propagation? When you add or change a DNS record, the change doesn't take effect everywhere instantly. DNS propagation is the process of your updated records spreading across DNS servers worldwide. Until propagation completes, some servers may still have the old records (or no records at all). This is why domain verification in SendKit can sometimes take minutes to hours after you add the required DNS records. ## How DNS works DNS is a distributed system. There's no single server that stores all DNS records. Instead, records are cached across thousands of servers worldwide in a hierarchy: Publishes your DNS records. Delegate queries to the correct TLD servers (`.com`, `.dev`, `.io`, etc.). Delegate queries to your provider's authoritative nameservers. ISPs, Google (`8.8.8.8`), and Cloudflare (`1.1.1.1`) cache your records and serve them to end users. Applications like SendKit query recursive resolvers to look up your DNS records. When you update a record at your DNS provider, recursive resolvers around the world still have the old record cached. They'll keep serving the old record until the cache expires. ## TTL (Time to Live) TTL controls how long a DNS record is cached before resolvers check for updates. It's measured in seconds. | TTL | Duration | Propagation speed | | ----- | --------- | ----------------- | | 300 | 5 minutes | Fast | | 3600 | 1 hour | Standard | | 86400 | 24 hours | Slow | When you set a TTL of 3600 (1 hour), resolvers will cache your record for up to 1 hour before checking for changes. This means changes can take up to 1 hour to propagate. SendKit recommends a TTL of **3600** (1 hour) for all DNS records. This is a good balance between propagation speed and DNS performance. ## Why propagation takes time Several factors affect how long propagation takes: ### 1. Previous TTL If your domain previously had a different record with a high TTL (e.g., 86400 — 24 hours), resolvers that cached the old record will wait for that TTL to expire before fetching the new one. The propagation time depends on the **old** TTL, not the new one. ### 2. Resolver caching behavior Not all resolvers respect TTL exactly. Some ISP resolvers cache records longer than the specified TTL to reduce load. There's nothing you can do about this — it resolves itself over time. ### 3. Negative caching If a resolver looked up your record **before** you added it and got a "no record found" response, it caches that negative result too. This negative cache also has a TTL (defined by the SOA record), typically 1–24 hours. This is why verification can sometimes take longer if SendKit checks your domain before you've added the records. ## How to check propagation You can verify if your DNS records have propagated by querying different DNS resolvers: ### Using dig (macOS/Linux) ```bash theme={null} # Check against Google's resolver dig @8.8.8.8 sendkit._domainkey.yourdomain.com TXT # Check against Cloudflare's resolver dig @1.1.1.1 sendkit._domainkey.yourdomain.com TXT # Check against your authoritative nameserver dig @ns1.yourprovider.com sendkit._domainkey.yourdomain.com TXT ``` ### Using nslookup (Windows) ```bash theme={null} nslookup -type=TXT sendkit._domainkey.yourdomain.com 8.8.8.8 ``` If the record appears when querying your authoritative nameserver but not Google's resolver, propagation is still in progress. ## Tips for faster propagation 1. **Lower the TTL before making changes** — if you know you'll be updating DNS records, lower the TTL to 300 (5 minutes) a day before. This ensures the old high-TTL cache expires before you make the change. 2. **Add all records at once** — add all SendKit DNS records (DKIM, SPF, MX, and optionally DMARC) at the same time to avoid multiple propagation waits. 3. **Double-check your records** — typos cause "record not found" errors that look like propagation issues. Copy values directly from the SendKit domain detail page. 4. **Be patient** — most records propagate within minutes to a few hours. In rare cases, it can take up to 48 hours. ## Propagation and SendKit verification SendKit automatically checks pending domains on a schedule: | Time since domain added | Check frequency | | ----------------------- | ---------------- | | First 2 hours | Every 10 minutes | | 2–12 hours | Every 30 minutes | | 12–72 hours | Every 60 minutes | You can also click **Refresh** on the domain detail page to trigger a manual check at any time. If your records are correct but verification fails, wait 30 minutes and try again. The most common cause is that SendKit's resolver hasn't received the updated records yet. ## FAQ Most likely, DNS propagation hasn't completed yet. Verify the records using `dig` against your authoritative nameserver. If they appear there but not on Google (8.8.8.8), wait for propagation. If they don't appear anywhere, double-check the record name and value at your DNS provider. You can't force global propagation, but you can minimize the wait by lowering the TTL before making changes. Once records are published, propagation depends on caches expiring across the internet. Changing nameservers triggers its own propagation (for the NS records). Your DNS records then need to propagate from the new provider. This can cause a temporary period where records are unavailable. # MX Records Source: https://docs.sendkit.dev/academy/authentication/mx-records Learn what MX records are and how they enable bounce and complaint handling. ## What are MX records? MX (Mail Exchange) records are DNS records that tell the internet where to deliver emails for a domain. When someone sends an email to `hello@acme.com`, the sending server looks up the MX records for `acme.com` to find out which mail server should receive the email. MX records are the postal address of the email world — they direct mail to the right destination. ## How MX records work The sending server needs to find out where to deliver the email. The server looks up MX records for `acme.com` and finds `mail.acme.com` with priority 10. The server connects to `mail.acme.com` and delivers the email. An MX record has two parts: | Part | Description | Example | | --------------- | ------------------------------- | --------------- | | **Mail server** | The hostname that handles email | `mail.acme.com` | | **Priority** | Lower number = higher priority | `10` | ## Priority and failover You can have multiple MX records with different priorities. The sending server tries the lowest number first: | Priority | Mail server | Role | | -------- | ---------------- | ---------------------------------------- | | 10 | `mail1.acme.com` | Primary — tried first | | 20 | `mail2.acme.com` | Backup — tried if primary is unavailable | If the primary server is down, the sending server automatically tries the next one. This gives you redundancy. ## MX records and SendKit When you add a domain in SendKit, we generate an MX record for the `send` subdomain: | Field | Value | | ------------ | ----------------------------------- | | **Type** | MX | | **Name** | `send.yourdomain.com` | | **Value** | Provided on your domain detail page | | **Priority** | 10 | | **TTL** | 3600 | ### Why does SendKit need an MX record? SendKit uses the MX record on the `send` subdomain for two critical purposes: **1. Bounce handling** When an email can't be delivered (invalid address, full mailbox, etc.), the recipient's mail server sends a bounce notification back. The MX record tells it where to send that notification — back to SendKit, so we can: * Mark the email as bounced in your dashboard * Trigger the `email.bounced` webhook * Track your bounce rate **2. Complaint handling** When a recipient marks your email as spam, their email provider sends a complaint notification (via feedback loops). The MX record ensures these complaints reach SendKit so we can: * Mark the contact as complained * Add them to the suppression list * Trigger the `email.complained` webhook Without the MX record, you'd be sending emails blind — with no visibility into bounces or complaints. The MX record is on the `send` subdomain only. It does not affect your root domain's email delivery. Your regular email (Google Workspace, Outlook, etc.) is not impacted. ## MX records vs other DNS records | Record | Purpose in email | | --------- | ------------------------------------------------------------------- | | **MX** | Directs where to deliver email (and bounce/complaint notifications) | | **SPF** | Declares who can send email for the domain | | **DKIM** | Signs emails to prove authenticity | | **DMARC** | Defines policy for failed authentication | MX handles **inbound** email routing. SPF, DKIM, and DMARC handle **outbound** email authentication. ## Common MX issues | Problem | Cause | Fix | | ---------------------- | ----------------------------------------- | ----------------------------------------------------------------------- | | Bounces not tracked | MX record missing or incorrect | Add the MX record from your SendKit domain detail page | | MX record not found | Wrong subdomain name | Make sure it's on `send.yourdomain.com`, not your root domain | | Conflicting MX records | Multiple MX records on the same subdomain | Remove any MX records on `send.yourdomain.com` that aren't from SendKit | ## FAQ No. The MX record is on the `send` subdomain (e.g., `send.acme.com`), not your root domain. Your existing email delivery through Google Workspace, Outlook, or any other provider is completely unaffected. That's fine — SendKit's MX record is on the `send` subdomain, which is separate from your root domain's MX records. They don't conflict. Yes. The MX record is one of the three required DNS records for domain verification in SendKit (along with SPF and DKIM). # SPF Source: https://docs.sendkit.dev/academy/authentication/spf Understand how SPF works and why it's essential for email authentication. ## What is SPF? SPF (Sender Policy Framework) is an email authentication protocol that lets you declare which mail servers are allowed to send emails on behalf of your domain. It's one of the first checks a receiving mail server performs when an email arrives. Without SPF, anyone can send an email that claims to come from your domain. SPF prevents this by publishing a list of authorized senders in your DNS. ## How SPF works When someone sends an email from `hello@acme.com`, the recipient's mail server: 1. Looks up the SPF record for `acme.com` in DNS 2. Gets a list of IP addresses and servers authorized to send for that domain 3. Checks if the sending server's IP is on that list 4. Returns a **pass** or **fail** result The email leaves your server and arrives at the recipient's mail server. The recipient's server looks up the SPF record for `acme.com` and finds `v=spf1 include:sendkit.dev ~all`. The server checks if the sending IP is listed in the SPF record. **Pass** — the IP is authorized, email is accepted. **Fail** — the IP is not authorized, email is flagged or rejected. ## SPF record syntax An SPF record is a TXT record in your DNS. Here's the anatomy of a typical record: ``` v=spf1 include:sendkit.dev ~all ``` | Part | Meaning | | --------------------- | ---------------------------------------------------------- | | `v=spf1` | Version identifier — always `spf1` | | `include:sendkit.dev` | Authorize all servers listed in SendKit's SPF record | | `~all` | Soft fail for any server not listed (see qualifiers below) | ### Mechanisms Mechanisms define who is authorized to send: | Mechanism | Description | Example | | --------- | ------------------------------------------ | --------------------- | | `include` | Authorize another domain's SPF record | `include:sendkit.dev` | | `ip4` | Authorize a specific IPv4 address or range | `ip4:192.168.1.1` | | `ip6` | Authorize a specific IPv6 address or range | `ip6:2001:db8::/32` | | `a` | Authorize the domain's A record IP | `a` | | `mx` | Authorize the domain's MX record IPs | `mx` | | `all` | Match everything (used at the end) | `~all` | ### Qualifiers Qualifiers tell the receiving server what to do with emails that match (or don't match) a mechanism: | Qualifier | Symbol | Meaning | | --------- | ------------- | ------------------------------------------------------- | | Pass | `+` (default) | The server is authorized | | Fail | `-` | The server is **not** authorized — reject the email | | Soft fail | `~` | The server is probably not authorized — accept but mark | | Neutral | `?` | No opinion — treat as if there's no SPF | **Recommendation:** Use `~all` (soft fail) while setting up, then switch to `-all` (hard fail) once you're confident all legitimate senders are listed. ## The 10-lookup limit SPF has a hard limit of **10 DNS lookups** per evaluation. Each `include`, `a`, `mx`, and `redirect` mechanism counts as one lookup. If your record exceeds 10 lookups, the SPF check automatically fails. This is a common problem when you use multiple email services (SendKit, Google Workspace, marketing tools, etc.), each adding their own `include`. ### How to check your lookup count Count each `include` in your SPF record. Then count the `include` statements inside each of those records (they're recursive). The total must be 10 or fewer. ### How to stay under the limit * **Use `ip4`/`ip6` instead of `include`** when possible — IP mechanisms don't count as lookups * **Remove unused includes** — if you stopped using a service, remove it from SPF * **Use subdomains** — send different types of email from different subdomains, each with their own SPF record * **Flatten your SPF record** — replace nested includes with their resolved IPs (but you'll need to update them if the IPs change) ## SPF with SendKit When you add a domain in SendKit, we generate an SPF record for the `send` subdomain. This keeps your root domain's SPF record clean and avoids conflicts with other services. | Field | Value | | --------- | ----------------------------------- | | **Type** | TXT | | **Name** | `send.yourdomain.com` | | **Value** | Provided on your domain detail page | | **TTL** | 3600 | Since SendKit uses a subdomain (`send.yourdomain.com`), it doesn't add to your root domain's lookup count. ## Common SPF issues | Problem | Cause | Fix | | ------------- | -------------------------------- | ---------------------------------------------------- | | SPF permerror | More than 10 DNS lookups | Reduce includes, use IPs, or split across subdomains | | SPF softfail | Sending server not in SPF record | Add the missing `include` or IP | | SPF none | No SPF record found | Add the SPF TXT record to your DNS | | SPF temperror | DNS timeout during lookup | Usually transient — retry. Check your DNS provider | ## FAQ No. A domain must have exactly **one** SPF TXT record. If you have multiple, SPF evaluation will fail. Combine all authorized senders into a single record. No. SPF checks the **envelope sender** (Return-Path), not the visible "From" header. This is why SPF alone isn't enough — you need DKIM and DMARC to protect the "From" address that recipients see. `~all` (soft fail) tells receiving servers that unauthorized senders should be treated with suspicion but not rejected. `-all` (hard fail) tells them to reject unauthorized senders outright. Start with `~all` and move to `-all` when you're confident in your setup. # CAN-SPAM Source: https://docs.sendkit.dev/academy/compliance/can-spam Understand the CAN-SPAM Act and what it requires for commercial email. ## What is CAN-SPAM? The CAN-SPAM Act (Controlling the Assault of Non-Solicited Pornography And Marketing Act) is a United States federal law enacted in 2003 that sets rules for commercial email. It applies to any email whose primary purpose is advertising or promoting a commercial product or service. Despite its name, CAN-SPAM doesn't ban spam. Instead, it establishes requirements that commercial emailers must follow — and penalties for violations. ## Who does CAN-SPAM apply to? CAN-SPAM applies to you if: * You send commercial or promotional emails * Your recipients include anyone in the United States * You or your business operates in the United States It doesn't matter where your business is physically located. If you send commercial email to US recipients, CAN-SPAM applies. CAN-SPAM primarily covers **marketing emails**. Transactional emails (order confirmations, password resets, shipping notifications) are largely exempt, as long as they don't contain primary marketing content. ## Requirements ### 1. Don't use false or misleading header information The `From`, `To`, `Reply-To`, and routing information must be accurate and identify the person or business that initiated the email. **Do:** Use your real business name and a valid email address. **Don't:** Spoof the sender name or use a fake reply-to address. ### 2. Don't use deceptive subject lines The subject line must accurately reflect the content of the email. **Do:** "New features in SendKit this month" **Don't:** "RE: Your order has shipped" (when there's no order) ### 3. Identify the message as an ad If the email is an advertisement, it must be clearly identified as such. The law gives flexibility on how to do this — there's no required format. ### 4. Include your physical address Every commercial email must include your valid physical postal address. This can be: * A street address * A PO Box registered with the US Postal Service * A private mailbox registered with a commercial mail receiving agency ### 5. Tell recipients how to opt out You must provide a clear and conspicuous way for recipients to opt out of future emails. This is typically an unsubscribe link. Requirements for the opt-out mechanism: * Must be easy to find and use * Must be able to process opt-out requests for at least 30 days after the email is sent * Cannot require the recipient to pay a fee, provide information beyond their email address, or take any steps other than replying or visiting a single page ### 6. Honor opt-out requests promptly You must process opt-out requests within **10 business days**. Once processed, you cannot: * Send further commercial emails to that address * Sell or transfer the address to another party * Have another party send emails on your behalf to that address 10 business days is the legal maximum. Industry expectation (and best practice) is to process unsubscribes **immediately**. SendKit processes unsubscribes in real time. ### 7. Monitor what others do on your behalf If you hire another company to send emails for you, you're still legally responsible for compliance. You can't outsource your way out of CAN-SPAM. ## Penalties CAN-SPAM violations can result in penalties of up to **\$51,744 per email**. The FTC, state attorneys general, and ISPs can all bring enforcement actions. In practice, penalties are typically imposed on egregious violators — businesses that send large volumes of deceptive spam. But even legitimate businesses should comply to avoid risk and maintain good sending practices. ## Transactional email exemptions CAN-SPAM distinguishes between **commercial** and **transactional** emails: **Transactional emails** are largely exempt from CAN-SPAM requirements. They don't need: * An unsubscribe link * A physical address * An "ad" identification To qualify as transactional, the email's primary purpose must be one of: * Completing a transaction the recipient agreed to (order confirmation, receipt) * Providing warranty, recall, or safety information about a purchased product * Notifying about a change in terms, features, or account status * Providing information about an ongoing subscription or membership * Delivering goods or services as part of a transaction If a transactional email contains marketing content that is more prominent than the transactional content, it may be reclassified as commercial and subject to all CAN-SPAM requirements. ## Checklist for compliance * [ ] `From` name and email are accurate and identify your business * [ ] Subject line accurately reflects the email content * [ ] Physical postal address is included * [ ] Unsubscribe link is visible and functional * [ ] Unsubscribe requests are honored within 10 business days * [ ] Email is identified as an ad (if applicable) * [ ] You're not using deceptive headers or subject lines ## FAQ No. Unlike GDPR and LGPD, CAN-SPAM does not require prior consent to send commercial emails. You can send unsolicited commercial email as long as you follow all the requirements above. However, opt-in is still a best practice for deliverability and reputation. Yes. CAN-SPAM applies to all commercial email, including business-to-business communications. There's no exemption for B2B. Yes. A PO Box registered with the US Postal Service or a private mailbox registered with a commercial mail receiving agency (like a UPS Store) satisfies the physical address requirement. # GDPR Source: https://docs.sendkit.dev/academy/compliance/gdpr Understand how GDPR affects email sending and what you need to do to comply. ## What is GDPR? The General Data Protection Regulation (GDPR) is a European Union regulation that governs how personal data is collected, processed, and stored. It took effect on May 25, 2018, and is one of the strictest data protection laws in the world. For email sending, GDPR sets strict rules about consent, data handling, and the rights of your recipients. ## Who does GDPR apply to? GDPR applies to you if: * Your business is based in the EU/EEA * You process personal data of individuals in the EU/EEA — regardless of where your business is located * You send emails to recipients in the EU/EEA If you have any EU/EEA subscribers or users, GDPR applies to your email sending. ## Key principles for email ### 1. Lawful basis for processing You need a **lawful basis** to send someone an email. For email marketing, the relevant bases are: **Consent** — the recipient has explicitly opted in to receive your emails. This is the most common and safest basis for marketing emails. **Legitimate interest** — you have a genuine business reason to contact the person, and their privacy rights don't override that interest. This is harder to rely on and requires a documented assessment. For transactional emails (order confirmations, account notifications), the lawful basis is typically **contract performance** — the email is necessary to fulfill a service the recipient signed up for. ### 2. Explicit consent for marketing GDPR requires **explicit, informed, freely given** consent for marketing emails. This means: **Must do:** * Use a clear opt-in mechanism (unchecked checkbox, separate signup form) * Explain what the recipient is signing up for ("Weekly product updates from SendKit") * Keep records of when and how consent was obtained **Must not:** * Use pre-checked checkboxes * Bundle consent with terms of service ("By creating an account, you agree to receive marketing emails") * Use vague language ("We may contact you from time to time") Under GDPR, silence or inactivity is not consent. A pre-checked checkbox or "opt-out" model (where the user must uncheck to avoid receiving emails) does not constitute valid consent. ### 3. Right to withdraw consent Recipients must be able to withdraw consent as easily as they gave it. In practice, this means: * Every marketing email must have an unsubscribe link * Unsubscribing must be a one-click or two-click process * Withdrawal must be processed promptly ### 4. Right to access Recipients can request a copy of all personal data you hold about them. For email, this includes: * Their email address and any associated data (name, preferences) * Email sending history * Consent records * Any tracking data (opens, clicks) ### 5. Right to erasure (Right to be forgotten) Recipients can request that you delete all their personal data. When a request is received, you must: * Delete their contact record * Remove them from all lists * Delete any associated tracking data * Confirm deletion to the recipient ### 6. Right to data portability Recipients can request their data in a commonly used, machine-readable format (like CSV or JSON) so they can transfer it to another service. ## Consent records GDPR requires that you can **prove** consent was given. For each subscriber, you should store: | Data point | Example | | ------------------------------ | ------------------------------------ | | **What** they consented to | "Weekly product newsletter" | | **When** they consented | 2026-01-15 14:32:00 UTC | | **How** they consented | Signup form on acme.com/newsletter | | **IP address** (optional) | 203.0.113.42 | | **Double opt-in confirmation** | Confirmed on 2026-01-15 14:35:00 UTC | If a recipient disputes their consent, you need this evidence. ## Double opt-in Double opt-in is a two-step process: 1. Recipient enters their email in your signup form 2. They receive a confirmation email with a link 3. They click the link to confirm their subscription While not strictly required by GDPR, double opt-in is **strongly recommended** because: * It proves the email address owner actually consented (not someone else using their address) * It creates a clear consent record * It reduces bounces and fake signups * Regulators view it favorably ## Data processing agreements If you use a service like SendKit to send emails, you're a **data controller** and SendKit is a **data processor**. GDPR requires a **Data Processing Agreement (DPA)** between controller and processor. A DPA defines: * What data is processed * How it's processed * Security measures in place * What happens to data when the agreement ends ## Email tracking and GDPR Open tracking (via pixel) and click tracking collect personal data (the recipient's behavior). Under GDPR: * You should disclose tracking in your privacy policy * Consider whether tracking is necessary (data minimization principle) * Provide a way for recipients to opt out of tracking SendKit allows you to enable or disable open tracking and click tracking per domain from the domain configuration page. If tracking raises GDPR concerns, you can disable it. ## Checklist for compliance * [ ] Marketing emails only go to recipients who explicitly opted in * [ ] Consent was recorded with what, when, and how * [ ] Every marketing email has a working unsubscribe link * [ ] You can process data access, erasure, and portability requests * [ ] A Data Processing Agreement is in place with SendKit * [ ] Your privacy policy covers email data collection and tracking * [ ] You don't use pre-checked checkboxes or bundled consent ## FAQ Transactional emails don't need marketing consent — they're sent under the "contract performance" lawful basis. However, GDPR's data protection principles still apply to transactional emails. You must still handle the recipient's data securely and respect their rights (access, erasure, etc.). Technically no. If you collected email addresses before GDPR without explicit consent, you need to re-obtain consent. Many companies sent "re-consent" campaigns when GDPR took effect. If you haven't done this, you should stop emailing those contacts for marketing purposes. GDPR fines can reach up to 20 million euros or 4% of annual global turnover, whichever is higher. In practice, fines vary based on the severity of the violation, the number of people affected, and the organization's cooperation with regulators. # LGPD Source: https://docs.sendkit.dev/academy/compliance/lgpd Understand how Brazil's LGPD affects email sending and what you need to comply. ## What is LGPD? The LGPD (Lei Geral de Proteção de Dados Pessoais) is Brazil's general data protection law, enacted in September 2020. It regulates how personal data of individuals in Brazil is collected, processed, stored, and shared. LGPD is heavily inspired by GDPR and shares many of the same principles, but has important differences that Brazilian businesses and any company processing data of Brazilian residents need to understand. ## Who does LGPD apply to? LGPD applies to you if: * You process personal data of individuals located in Brazil * The data processing takes place in Brazil * The data was collected in Brazil * You offer goods or services to individuals in Brazil It doesn't matter where your company is headquartered. If you email Brazilian recipients, LGPD applies. ## Key principles for email ### 1. Legal basis for processing Like GDPR, LGPD requires a **legal basis** to process personal data. For email marketing, the relevant bases are: **Consent** — the most straightforward basis. The recipient explicitly agrees to receive your emails. **Legitimate interest** — you have a genuine reason to contact the person, balanced against their privacy rights. LGPD requires a **Legitimate Interest Assessment (LIA)** documenting this balance. For transactional emails, the basis is typically **contract execution** or **regular exercise of rights** — the email is necessary for a service the user has with you. ### 2. Consent requirements LGPD consent for email marketing must be: | Requirement | What it means | | --------------- | ----------------------------------------------------------- | | **Free** | Not coerced or bundled with other terms | | **Informed** | The recipient knows what they're consenting to | | **Unambiguous** | Clear affirmative action (not silence or pre-checked boxes) | | **Specific** | For a specific purpose ("marketing emails from SendKit") | Like GDPR, LGPD does not accept pre-checked checkboxes or bundled consent as valid. The recipient must take an explicit action to opt in. ### 3. Right to information At the time of data collection, you must inform the recipient about: * What data you're collecting * Why you're collecting it (purpose) * How long you'll keep it * Who you'll share it with (including email service providers like SendKit) * How they can exercise their rights This is typically handled through a privacy policy linked from your signup form. ### 4. Rights of data subjects LGPD grants recipients several rights: | Right | Description | | ---------------- | --------------------------------------------------- | | **Confirmation** | Confirm whether their data is being processed | | **Access** | Request a copy of their personal data | | **Correction** | Request correction of inaccurate data | | **Deletion** | Request deletion of unnecessary or excessive data | | **Portability** | Request data in a standard format for transfer | | **Revocation** | Withdraw consent at any time | | **Information** | Know which third parties their data was shared with | For email, the most common requests are **deletion** (remove me from your lists) and **revocation** (I withdraw my consent for marketing emails). ### 5. Data minimization Only collect and process the data you actually need. For email sending, this means: **Necessary:** Email address, name (for personalization), consent record **Probably not necessary:** Phone number, physical address, date of birth (unless relevant to your product) Don't collect extra data "just in case" — this violates the data minimization principle. ## LGPD vs GDPR | Aspect | LGPD | GDPR | | ---------------------------- | ---------------------------------------------------- | ---------------------------------- | | **Geographic scope** | Data of individuals in Brazil | Data of individuals in EU/EEA | | **Legal bases** | 10 legal bases | 6 legal bases | | **DPO requirement** | Required for all organizations | Required only in specific cases | | **Consent for marketing** | Explicit consent required | Explicit consent required | | **Data breach notification** | "Reasonable time" (no specific deadline) | 72 hours | | **Fines** | Up to 2% of revenue, max R\$50 million per violation | Up to 4% of global revenue or €20M | | **Enforcement** | ANPD (Autoridade Nacional de Proteção de Dados) | National DPAs in each EU country | ### Notable differences **More legal bases** — LGPD has 10 legal bases for processing (vs GDPR's 6), including "protection of credit" and "regular exercise of rights." **DPO for everyone** — LGPD requires every organization that processes personal data to appoint a Data Protection Officer (DPO), called "Encarregado" in Portuguese. GDPR only requires a DPO in specific cases. **Vaguer breach notification** — LGPD requires notification in a "reasonable time" rather than GDPR's strict 72-hour deadline. ## The role of ANPD The ANPD (Autoridade Nacional de Proteção de Dados) is Brazil's data protection authority. It's responsible for: * Issuing guidance on LGPD compliance * Investigating complaints * Imposing penalties * Approving codes of conduct and certifications ANPD has been actively issuing guidelines and increasing enforcement since 2023. ## Penalties | Penalty type | Maximum | | ------------- | --------------------------------------------------------- | | Warning | With a deadline to fix the issue | | Simple fine | 2% of revenue, up to R\$50 million per violation | | Daily fine | For ongoing violations | | Data blocking | Prohibition on using the data until the issue is resolved | | Data deletion | Mandatory deletion of the data involved | ## Checklist for compliance * [ ] Marketing emails only go to recipients who gave explicit consent * [ ] Consent records include what, when, how, and purpose * [ ] Privacy policy is accessible and explains data processing practices * [ ] Every marketing email has a working unsubscribe link * [ ] You can process data access, correction, deletion, and portability requests * [ ] A DPO (Encarregado) has been appointed * [ ] Data processing agreements are in place with third-party processors (like SendKit) * [ ] Only necessary data is collected (data minimization) ## FAQ Yes, if you process personal data of individuals in Brazil or offer goods/services to people in Brazil. The company's location doesn't matter — what matters is the location of the data subjects. It's possible but risky. You'd need to conduct and document a Legitimate Interest Assessment (LIA), and be prepared to justify your decision to the ANPD. Consent is the safer and more common approach for marketing emails in Brazil. Yes. Under LGPD, all organizations that process personal data must appoint an Encarregado (DPO). This can be an internal employee or an external service. The DPO's contact information must be publicly available. Not explicitly required, but strongly recommended. Double opt-in provides strong evidence of consent and is viewed favorably by the ANPD. It also protects you from fraudulent signups. # Bounce Handling Source: https://docs.sendkit.dev/academy/deliverability/bounce-handling Learn the difference between hard and soft bounces and how to handle them. ## What is a bounce? A bounce happens when an email can't be delivered to the recipient. The receiving mail server sends back a notification explaining why the delivery failed. Bounces are a normal part of sending email, but high bounce rates damage your [sender reputation](/academy/deliverability/sender-reputation). ## Types of bounces ### Hard bounce A hard bounce is a **permanent** delivery failure. The email will never be deliverable to this address. Common causes: | Cause | Example | | --------------------- | ---------------------------------------------------- | | Address doesn't exist | `nobody@acme.com` — no such mailbox | | Domain doesn't exist | `hello@nonexistent.com` — domain has no MX records | | Blocked by recipient | The receiving server permanently rejects your emails | **What to do:** Remove hard-bounced addresses immediately. Never send to them again. Continuing to send to hard-bounced addresses signals to email providers that you don't maintain your list. ### Soft bounce A soft bounce is a **temporary** delivery failure. The email might be deliverable if you try again later. Common causes: | Cause | Example | | ------------------------------ | ----------------------------------------------- | | Mailbox full | Recipient's inbox has reached its storage limit | | Server temporarily unavailable | Receiving server is down or overloaded | | Message too large | Email exceeds the recipient's size limit | | Rate limited | Receiving server is throttling your deliveries | **What to do:** SendKit automatically retries soft bounces. If an address soft bounces **3 times**, SendKit automatically suppresses it — treating it as a hard bounce. On successful delivery, the soft bounce counter resets. ## Bounce codes Bounce notifications include SMTP status codes that explain the failure. The codes follow a pattern: | Code | Category | Meaning | | ----- | ----------- | --------------------------------------------------- | | 5.1.1 | Hard bounce | Address doesn't exist | | 5.1.2 | Hard bounce | Domain doesn't exist | | 5.2.1 | Soft bounce | Mailbox full / disabled | | 5.2.2 | Soft bounce | Over quota | | 5.3.0 | Soft bounce | Other mail system issue | | 5.4.1 | Soft bounce | No answer from host | | 5.7.1 | Hard/Soft | Rejected by policy (could be content or reputation) | The first digit indicates the category: * **4.x.x** — temporary failure (soft bounce) * **5.x.x** — permanent failure (hard bounce, with some exceptions) ## Bounce handling in SendKit SendKit handles bounces automatically: ### Hard bounces 1. The email is marked as **bounced** in your dashboard 2. The `email.bounced` webhook is triggered 3. The address is added to the [suppression list](/academy/email-concepts/suppression-lists) — future sends to this address are automatically blocked ### Soft bounces 1. SendKit retries delivery automatically 2. If delivery succeeds on retry, the email is marked as **delivered** and the soft bounce counter for that address resets 3. If all retries fail, the email is marked as **bounced** 4. After **3 soft bounces** to the same address, it's automatically added to the suppression list ### The suppression list The suppression list prevents you from sending to addresses that have previously hard bounced. This is critical for maintaining your reputation. If you try to send to a suppressed address, SendKit blocks the send and returns an error. Do not remove addresses from the suppression list unless you have confirmed the address is now valid (e.g., the recipient contacted you to confirm). Repeatedly sending to invalid addresses will damage your reputation. ## Bounce rate thresholds | Bounce rate | Status | Action | | ----------- | -------------- | -------------------------------------------------- | | \< 5% | Healthy | Normal operations | | 5–10% | Warning | Review your list hygiene | | > 10% | Sending paused | SendKit automatically pauses sending for your team | SendKit evaluates reputation with a minimum of 200 emails in the last 24 hours. If your bounce rate exceeds **10%**, sending is automatically paused and your team admins are notified. ## Preventing bounces ### At collection * **Validate email addresses at signup** — use the SendKit [email validation API](/api-reference/endpoint/validate-email) to catch typos and invalid addresses before they enter your list * **Use double opt-in** — send a confirmation email and only add contacts who confirm. This eliminates typos and fake addresses * **Don't accept catch-all addresses blindly** — some domains accept all emails regardless of the mailbox. These can still bounce later ### Ongoing * **Clean your list regularly** — remove addresses that haven't engaged in 90+ days * **Monitor bounce metrics** — check your dashboard after every campaign or batch send * **Honor suppression lists** — never circumvent the suppression list ## FAQ Under 2%. If you're consistently above 2%, you need to improve your list hygiene. Above 5% is critical and can result in email providers throttling or blocking your emails. No. Hard bounces are permanent. Retrying wastes resources and hurts your reputation. Remove hard-bounced addresses from your list immediately. Email addresses become invalid over time. People leave companies, abandon personal accounts, or reach storage limits. This is why regular list cleaning is important — even a "clean" list degrades over time. If a hard-bounced address is now valid again (e.g., the mailbox was recreated), you can remove it from the suppression list in your SendKit dashboard. But verify it first — don't assume. # Domain Warmup Source: https://docs.sendkit.dev/academy/deliverability/domain-warmup Understand why new domains need to be warmed up and how the process works. ## What is domain warmup? Domain warmup is the process of gradually increasing the volume of emails sent from a new domain over time. New domains have no sending history — email providers don't know whether to trust them. Sending a large volume immediately triggers spam filters and can permanently damage your domain's reputation. Warmup builds trust by showing email providers a pattern of legitimate, low-volume sending that gradually increases. ## Why warmup matters Email providers use historical sending data to evaluate senders. A domain that has never sent email and suddenly starts sending thousands of messages looks suspicious — this is exactly what spammers do. Here's how email providers react to new domains: | Behavior | Provider reaction | | ------------------------------------- | ---------------------------------------------- | | Gradual volume increase over days | "This looks like a legitimate new sender" | | Sudden high volume from day one | "This looks like spam or a compromised domain" | | Consistent daily volume | "Predictable, trustworthy pattern" | | Erratic volume (0, 0, 5000, 0, 10000) | "Unpredictable, suspicious pattern" | ## How SendKit warmup works SendKit has a **built-in, automatic warmup system**. When you verify a new domain and send your first email, the 7-day warmup period begins. SendKit automatically detects your domain's age and applies the appropriate warmup schedule. Younger domains get a more conservative schedule because they have no established reputation anywhere — not just on SendKit. ### Young domains (less than 30 days old) | Day | Daily limit | | --- | ------------ | | 1 | 50 emails | | 2 | 100 emails | | 3 | 250 emails | | 4 | 500 emails | | 5 | 1,000 emails | | 6 | 1,500 emails | | 7 | 2,000 emails | | 8+ | No limit | ### Established domains (30+ days old) | Day | Daily limit | | --- | ------------ | | 1 | 200 emails | | 2 | 500 emails | | 3 | 1,000 emails | | 4 | 2,000 emails | | 5 | 3,500 emails | | 6 | 5,000 emails | | 7 | 7,500 emails | | 8+ | No limit | Daily limits reset at midnight (UTC). The warmup clock starts when you send your **first email** from the domain, not when you verify it. You can verify your domain in advance without starting the warmup timer. ### What happens when you hit the limit If you try to send more emails than your current daily limit allows, the API returns a `429` response: ```json theme={null} { "name": "warmup_limit", "message": "Domain warmup limit reached for example.com. Daily limit: 200 emails. Sent today: 200. Warmup completes on 2026-03-14.", "domain": "example.com", "daily_limit": 200, "emails_sent_today": 200, "warmup_day": 3, "warmup_ends_at": "2026-03-14T00:00:00Z" } ``` Use the `warmup_ends_at` and `daily_limit` fields to plan your sending. ## Best practices during warmup ### Send to engaged recipients first During the first few days, prioritize recipients who are most likely to open and interact with your emails: * New signups who just created an account * Users who recently used your product * Contacts who opted in directly Positive engagement (opens, clicks, replies) during warmup helps build your reputation faster. ### Avoid cold or old lists Do not send to purchased lists, scraped addresses, or contacts who haven't engaged in months. High bounce rates and complaints during warmup can permanently harm your domain's reputation before it's even established. ### Send every day Try to send emails every day during the warmup period. Consistent daily sending signals to email providers that you're a legitimate, active sender. Gaps in sending don't reset the warmup, but they reduce the strength of the reputation signal. ### Monitor metrics closely Check your SendKit dashboard daily during warmup: * **Bounce rate** should stay under 5% * **Complaint rate** should stay under 0.1% If any of these metrics spike, pause sending and investigate before continuing. ## Free plan daily limit In addition to the warmup schedule, **Free plan accounts are limited to 100 emails per day**, even after warmup completes. This limit resets at midnight (UTC). Upgrading to a paid plan removes the daily limit. ## Warmup and campaigns If you're planning a campaign during the warmup period, keep in mind that SendKit respects both the daily warmup limit and the daily plan limit. If either limit is reached mid-campaign, the campaign is marked as **partially sent** — the remaining contacts won't receive the email until you send the campaign again after the daily limit resets. Plan your campaign size around your current warmup day and daily limit to avoid partial sends. ## Common questions No. The warmup schedule is enforced automatically to protect your sending reputation. Skipping it risks having your emails flagged as spam from day one, which is much harder to recover from than waiting 7 days. Yes. Each verified domain has an independent warmup period. Adding a new domain starts a fresh 7-day warmup for that domain only. The warmup is based on calendar days since your first email, not sending days. If you skip a day, the schedule continues — your limits still increase as planned. Yes. Batch sends count against your daily warmup limit. If a batch would exceed the limit, the entire batch is rejected. Yes. Your reputation with another service is tied to their sending infrastructure (IPs). When you send through SendKit, the email comes from different infrastructure, so email providers need to learn to trust this new combination of your domain + SendKit's servers. SendKit automatically detects your domain's registration date. Domains registered less than 30 days ago use the young schedule, which has lower daily limits to protect your reputation during the critical early period. If we can't determine your domain's age, it defaults to the young schedule. # Email Throttling Source: https://docs.sendkit.dev/academy/deliverability/email-throttling Understand why email providers throttle delivery and how to handle it. ## What is email throttling? Email throttling happens when a receiving mail server intentionally slows down or temporarily rejects emails from a sender. Instead of accepting all your emails at once, the server accepts them at a controlled rate — or defers some with a "try again later" response. Throttling is different from blocking. A blocked sender is rejected entirely. A throttled sender is told to slow down and retry. ## Why providers throttle emails Email providers throttle for several reasons: ### 1. Volume protection Mail servers have capacity limits. If a sender tries to deliver 100,000 emails in a minute, the server may throttle to protect itself and its users. ### 2. Unknown sender When a domain or IP has little or no sending history, providers are cautious. They accept a small batch first, observe engagement (opens, not-spam, etc.), and gradually accept more. This is one reason [domain warmup](/academy/deliverability/domain-warmup) exists. ### 3. Reputation signals If your recent emails have generated complaints or bounces, providers may throttle future emails while they reassess your reputation. ### 4. Rate limits Most providers have explicit rate limits per sender. When you exceed them, additional emails are deferred. ## How throttling looks When a mail server throttles your emails, it responds with a **4xx temporary error code**: ``` 421 4.7.28 Too many emails from this sender. Try again later. ``` ``` 452 4.5.3 Too many recipients. Please try again. ``` The `4xx` code means "temporary rejection" — the server is telling the sender to retry later. This is different from a `5xx` code, which means permanent rejection. ## Throttling by provider Each email provider has different thresholds: ### Gmail * Throttles based on domain reputation and sending volume * New senders face stricter limits * Reputation improves as engagement data accumulates * Uses per-domain and per-IP limits ### Outlook/Hotmail * Has explicit rate limits that vary by sender reputation * Can be aggressive with new or low-reputation senders * Throttling often appears as `421` temporary deferrals ### Yahoo * Throttles based on volume, reputation, and complaint rates * Publishes a feedback loop to notify about complaints ## How SendKit handles throttling SendKit automatically handles throttled emails: 1. **Automatic retries** — when a receiving server returns a `4xx` code, SendKit queues the email for retry 2. **Exponential backoff** — retries are spaced out with increasing intervals to respect the provider's limits 3. **Smart scheduling** — for large sends, SendKit distributes delivery over time to avoid triggering throttles You don't need to implement retry logic yourself. If a throttled email eventually delivers, it's marked as **delivered** in your dashboard. If all retries are exhausted, it's marked as **failed**. ## Avoiding throttling ### Warm up your domain The most common cause of throttling for new SendKit users is sending too much too soon. Follow the [warmup schedule](/academy/deliverability/domain-warmup) and resist the urge to send high volumes early. ### Maintain your reputation A good sender reputation means higher rate limits. Keep your bounce rate low, complaint rate minimal, and engagement high. ### Spread large sends over time If you need to send a campaign to a large list, don't send it all at once. SendKit distributes delivery automatically, but planning your sends helps too: * Segment your list and send to smaller groups over hours or days * Send to your most engaged recipients first ### Don't send identical emails in bulk Emails with identical content sent to many recipients at once are a spam pattern. Even for legitimate campaigns, personalizing content (recipient name, relevant details) helps avoid throttling. ## Throttling vs bouncing It's important to understand the difference: | | Throttling | Bouncing | | ------------------------ | --------------------------- | --------------------------------- | | **Type** | Temporary deferral | Permanent or temporary rejection | | **Server response** | 4xx code | 5xx code (hard) or 4xx (soft) | | **Meaning** | "Slow down, try later" | "Can't deliver this email" | | **Action** | Automatic retry | Hard: suppress. Soft: retry | | **Impact on reputation** | Minimal if handled properly | Negative, especially hard bounces | ## FAQ It depends on the provider and the cause. For new senders during warmup, throttling typically eases as reputation builds over days to weeks. For sudden volume spikes, it may resolve within hours once your sending rate normalizes. Not necessarily. Throttled emails are deferred, not rejected. SendKit retries them automatically. Most throttled emails eventually get delivered, just with a delay. Emails that are eventually delivered appear as **delivered** in your dashboard. Emails where all retries were exhausted appear as **failed**. The `email.delivery_delayed` webhook fires when an email is being retried due to throttling. # Sender Reputation Source: https://docs.sendkit.dev/academy/deliverability/sender-reputation Understand how email providers evaluate your sending reputation and how to protect it. ## What is sender reputation? Sender reputation is a score that email providers (Gmail, Outlook, Yahoo, etc.) assign to your domain and IP addresses based on your email sending behavior. It directly determines whether your emails land in the inbox, the spam folder, or get rejected entirely. Think of it like a credit score for email. A good reputation means email providers trust you. A bad reputation means they don't. ## How reputation is calculated Email providers don't publish their exact algorithms, but the key factors are well known: ### Positive signals | Signal | Impact | | ---------------------------------------- | -------------------------------------- | | Low bounce rate | Shows you maintain a clean list | | Low complaint rate | Shows recipients want your emails | | High engagement (opens, clicks) | Shows your content is relevant | | Consistent sending volume | Shows predictable, legitimate behavior | | Proper authentication (SPF, DKIM, DMARC) | Shows you're a verified sender | ### Negative signals | Signal | Impact | | --------------------- | --------------------------------------------- | | High bounce rate | Suggests you're sending to invalid addresses | | High complaint rate | Suggests recipients consider your emails spam | | Sending to spam traps | Strong signal of poor list hygiene | | Sudden volume spikes | Suggests compromised account or spam behavior | | High unsubscribe rate | Suggests unwanted emails | ## Domain reputation vs IP reputation There are two layers of reputation: **Domain reputation** — tied to your domain (e.g., `acme.com`). This follows you regardless of which service you use to send emails. It's built over time based on all emails sent from your domain. **IP reputation** — tied to the IP address of the sending server. When you use SendKit, your emails are sent from shared or dedicated IPs managed by SendKit. Domain reputation is increasingly more important than IP reputation. Gmail, for example, weighs domain reputation heavily in their filtering decisions. ## Spam traps Spam traps are email addresses specifically designed to catch senders with poor list hygiene. There are three types: **Pristine traps** — email addresses that were never used by a real person. They're created by email providers and anti-spam organizations and seeded across the internet. If you send to one, it means you scraped or purchased your list. **Recycled traps** — old email addresses that were abandoned by their original owner and repurposed as traps. If you send to one, it means you haven't cleaned your list in a long time. **Typo traps** — addresses at common misspellings of popular domains (e.g., `gmial.com`, `yaho.com`). They catch senders who don't validate email addresses at signup. Hitting a spam trap is one of the most damaging things for your reputation. There's no notification when it happens — you'll just see deliverability decline. The only prevention is maintaining a clean, permission-based list. ## Monitoring your reputation ### Google Postmaster Tools Google Postmaster Tools is a free tool that shows how Gmail views your domain. It shows: * Domain reputation (High, Medium, Low, Bad) * IP reputation * Spam rate * Authentication success rates * Encryption rates You need to verify domain ownership to access the data. If you send any volume to Gmail users, this is essential. ### SendKit metrics SendKit tracks key deliverability metrics in your dashboard: * **Bounce rate** — percentage of emails that bounced * **Complaint rate** — percentage of emails marked as spam * **Delivery rate** — percentage of emails successfully delivered Monitor these regularly. Industry thresholds: | Metric | Healthy | Warning | Sending paused | | -------------- | ------- | -------- | -------------- | | Bounce rate | \< 5% | 5–10% | > 10% | | Complaint rate | \< 0.1% | 0.1–0.5% | > 0.5% | SendKit evaluates your reputation automatically. If your bounce rate exceeds **10%** or complaint rate exceeds **0.5%** (with a minimum of 200 emails in the last 24 hours), sending is automatically paused for your team. Google's own threshold for complaint rate is **0.1%** — exceeding it may cause Gmail to filter your emails to spam. ## Building and maintaining reputation ### For new domains New domains have no reputation — email providers don't know whether to trust you. This is why SendKit has an automatic [domain warmup](/academy/deliverability/domain-warmup) period that gradually increases your sending volume over 7 days. During warmup: 1. **Send to engaged recipients first** — people who have recently signed up or interacted with your product 2. **Keep volume low** — follow the warmup schedule 3. **Monitor metrics closely** — watch for bounces and complaints ### For established domains 1. **Clean your list regularly** — remove addresses that consistently bounce 2. **Honor unsubscribes immediately** — never send to someone who opted out 3. **Maintain consistent volume** — avoid sudden spikes in sending 4. **Authenticate properly** — ensure SPF, DKIM, and DMARC are all passing 5. **Segment your sending** — send relevant content to relevant recipients ## Recovering from a bad reputation If your reputation has degraded: 1. **Stop sending** to anyone who hasn't engaged recently 2. **Identify the cause** — high bounces? complaints? spam traps? 3. **Clean your list aggressively** — remove anyone who hasn't opened in 90+ days 4. **Start sending again slowly** — treat it like a warmup 5. **Only send to confirmed opt-ins** — double opt-in if possible Recovery takes time — typically 2–4 weeks of clean sending behavior. ## FAQ A new domain typically needs 2–4 weeks of consistent, clean sending to establish a positive reputation. The warmup period helps, but reputation continues to improve over months of good behavior. Partially. A new subdomain starts with no reputation of its own, but email providers may also consider the root domain's reputation. Using a subdomain isolates risk but doesn't completely bypass a damaged root domain reputation. Yes. A single campaign to a bad list can tank your reputation overnight. This is why monitoring metrics after every send is important, especially for campaigns. # Spam Filters Source: https://docs.sendkit.dev/academy/deliverability/spam-filters Learn how email providers decide what's spam and how to avoid their filters. ## How spam filters work Every email that arrives at Gmail, Outlook, Yahoo, or any other email provider passes through a spam filter. These filters analyze hundreds of signals to decide whether to deliver the email to the inbox, send it to spam, or reject it entirely. Spam filters have evolved far beyond simple keyword matching. Modern filters use machine learning, sender reputation, engagement data, and authentication results to make decisions. ## The filtering process When your email arrives at a recipient's mail server: Fail = likely spam. Bad reputation = likely spam. Spammy patterns = likely spam. Recipients ignoring your emails = likely spam. The recipient's past behavior with your emails influences the final decision: **Inbox**, **Spam**, or **Reject**. ## Key factors ### 1. Authentication Emails that fail SPF, DKIM, or DMARC are immediately suspicious. Proper authentication is the baseline — without it, everything else is irrelevant. ### 2. Sender reputation Your domain and IP reputation are the strongest signals. A sender with a history of low complaints and high engagement gets the benefit of the doubt. See [Sender Reputation](/academy/deliverability/sender-reputation). ### 3. Content Spam filters analyze your email content for patterns commonly associated with spam: **Things that trigger filters:** * ALL CAPS in subject lines * Excessive exclamation marks (!!!) * Known spam phrases ("Act now!", "Limited time offer!", "You've been selected!") * Misleading subject lines * Image-only emails with no text * URL shorteners (bit.ly, etc.) — they hide the real destination * Too many links * Large attachments * Broken HTML **Things that help:** * Clean, well-structured HTML * A good text-to-image ratio * A plain text version alongside HTML * A clear, descriptive subject line * An unsubscribe link (required by law for marketing emails) ### 4. Engagement Modern filters (especially Gmail) heavily weight engagement: | Signal | Interpretation | | ---------------------------------- | ----------------------------------------- | | Recipients open your emails | Positive — content is wanted | | Recipients click links | Positive — content is relevant | | Recipients reply | Very positive — genuine conversation | | Recipients move to spam | Very negative — content is unwanted | | Recipients delete without opening | Negative — content is irrelevant | | Recipients move from spam to inbox | Very positive — false positive correction | Gmail uses engagement data not just per-recipient but in aggregate. If many Gmail users mark your emails as spam, Gmail may start filtering your emails for all Gmail users. ### 5. Infrastructure Technical factors about how the email was sent: * **Reverse DNS (PTR record)** — the sending IP should have a valid PTR record * **TLS** — emails sent over encrypted connections are trusted more * **Sending patterns** — consistent volume is better than erratic spikes * **List-Unsubscribe header** — presence signals a legitimate sender ## Provider-specific behavior Each email provider has its own filtering logic: ### Gmail * Relies heavily on engagement and domain reputation * Uses machine learning trained on billions of emails * Tabs (Primary, Promotions, Social) further categorize non-spam emails * Google Postmaster Tools gives visibility into how Gmail views your domain ### Outlook/Hotmail * Uses Microsoft's SmartScreen filter * Relies more on IP reputation than other providers * Has a Junk Email Reporting Program (JMRP) for feedback * Can be stricter with new senders ### Yahoo * Uses DomainKey and DKIM heavily * Has its own complaint feedback loop (CFL) * Reputation is built per-domain ## What to do when emails go to spam 1. **Check authentication** — are SPF, DKIM, and DMARC all passing? Check the email headers. 2. **Check reputation** — use Google Postmaster Tools to see your domain reputation. 3. **Review content** — remove spammy language, fix broken HTML, add a plain text version. 4. **Check engagement** — are you sending to people who want your emails? 5. **Check your list** — remove inactive recipients, bounced addresses, and unsubscribes. 6. **Check volume** — did you suddenly increase sending volume? ## Email headers tell the story When debugging spam issues, always check the email headers. They show exactly what happened: ``` Authentication-Results: mx.google.com; dkim=pass header.d=acme.com; spf=pass; dmarc=pass; X-Spam-Status: No, score=-1.2 X-Spam-Score: -1.2 ``` A negative spam score is good (not spam). A positive score means the filter found suspicious signals. ## FAQ No. There's no way to guarantee inbox delivery. Each email provider makes its own decisions based on authentication, reputation, content, and recipient engagement. The best you can do is follow best practices consistently. Less than they used to. Modern filters are much more sophisticated than keyword matching. That said, using aggressive sales language combined with other negative signals (bad reputation, low engagement) can tip the balance. Focus on writing naturally and providing value. The Promotions tab is not spam — it's Gmail's categorization for marketing-style emails. Emails with promotional language, images, HTML templates, and unsubscribe links tend to land here. Transactional emails (receipts, password resets, notifications) usually land in Primary. # BIMI Source: https://docs.sendkit.dev/academy/domains/bimi Display your brand logo next to your emails in recipients' inboxes with BIMI. ## What is BIMI? BIMI (Brand Indicators for Message Identification) is an email standard that lets you display your brand's logo next to your emails in the recipient's inbox. Instead of a generic avatar or initials, recipients see your actual logo — making your emails instantly recognizable. Example of a BIMI logo displayed next to an email in the inbox. BIMI is a visual trust signal. It shows recipients that the email is legitimately from your organization and has passed email authentication checks. ## How BIMI works BIMI builds on top of DMARC. Here's the chain of trust: 1. **SPF and DKIM** authenticate the email 2. **DMARC** enforces a policy (`quarantine` or `reject`) on failing emails 3. **BIMI** tells the email client where to find your logo 4. The email client verifies the DMARC policy is enforced, then displays the logo Without a strong DMARC policy, BIMI won't work. This is by design — BIMI is a reward for properly authenticating your email. ``` SPF + DKIM → DMARC (quarantine or reject) → BIMI → Logo displayed ``` ## Prerequisites Before implementing BIMI, you need: 1. **A verified domain** in SendKit with SPF and DKIM passing 2. **A DMARC record** with `p=quarantine` or `p=reject` at `pct=100`. See the [DMARC guide](/academy/domains/dmarc) 3. **A logo** in SVG Tiny PS format (more details below) 4. **A mark certificate** (VMC or CMC) from a supported certificate authority ## Email client support Not all email clients support BIMI. Here's the current support: | Email client | VMC (Verified Mark Certificate) | CMC (Common Mark Certificate) | | ----------------- | ------------------------------- | ----------------------------- | | **Gmail** | Yes | Yes | | **Apple Mail** | Yes | Yes | | **Yahoo Mail** | Yes | Yes | | **Outlook (new)** | Coming soon | Coming soon | VMC requires a registered trademark. CMC is an alternative for organizations without a trademark — it requires demonstrating at least one year of consistent logo use. ## Implementing BIMI ### Step 1: Enforce DMARC Your DMARC record must have `p=quarantine` or `p=reject` with `pct=100` (all emails). If you're still on `p=none`, follow the [DMARC guide](/academy/domains/dmarc) to upgrade your policy first. ``` v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; ``` ### Step 2: Prepare your logo Your logo must meet these requirements: * **Format**: SVG Tiny PS (Portable/Secure) — a specific subset of SVG * **Shape**: Square aspect ratio * **Background**: Solid, non-transparent background (the logo will be displayed in a circle or square depending on the email client) * **Size**: Keep it under 32 KB A regular SVG file won't work. It must be specifically in the SVG Tiny PS format. Most certificate authorities provide tools to convert your logo. Host the SVG file on your web server over HTTPS. For example: `https://acme.com/brand/logo.svg` ### Step 3: Obtain a mark certificate A mark certificate proves that you own the logo. There are two types: **VMC (Verified Mark Certificate)** — requires a registered trademark with an intellectual property office recognized by the certificate authority. **CMC (Common Mark Certificate)** — for organizations without a registered trademark. Requires demonstrating at least one year of consistent, visible use of the logo. You can obtain certificates from: * DigiCert * GlobalSign * SSL.com The certificate authority will validate your logo ownership and issue a PEM certificate file. Host it on your web server over HTTPS alongside your logo. ### Step 4: Add the BIMI DNS record Add a TXT record to your DNS: | Field | Value | | --------- | --------------------------------------------------------------------------------------- | | **Type** | TXT | | **Name** | `default._bimi.yourdomain.com` | | **Value** | `v=BIMI1; l=https://acme.com/brand/logo.svg; a=https://acme.com/brand/certificate.pem;` | | **TTL** | 3600 | Replace the URLs with your actual logo and certificate locations. ## BIMI record parameters | Parameter | Required | Description | | --------- | -------- | ---------------------------------------------------------------- | | `v` | Yes | Version. Always `BIMI1` | | `l` | Yes | URL to your logo in SVG Tiny PS format (must be HTTPS) | | `a` | Yes | URL to your VMC or CMC certificate in PEM format (must be HTTPS) | ## Verifying your BIMI record After adding the DNS record, it may take a few days for email clients to start displaying your logo. You can verify your setup by: 1. Sending a test email to a Gmail or Yahoo address 2. Checking the email headers for `bimi=pass` in the `Authentication-Results` 3. Looking for your logo next to the email in the inbox Gmail may cache BIMI lookups. If your logo doesn't appear immediately, wait 24–48 hours and try again. ## FAQ The DNS record is free. However, you need a mark certificate (VMC or CMC), which is a paid certificate from a certificate authority. Prices vary by provider. Not necessarily. A VMC requires a registered trademark, but a CMC only requires one year of demonstrated logo use. The CMC option makes BIMI accessible to smaller organizations. BIMI won't work. Email clients require `p=quarantine` or `p=reject` at `pct=100` before they'll display BIMI logos. This ensures that only properly authenticated senders can show their logo. BIMI supports selectors, so you could in theory use different logos. In practice, most organizations use a single `default` selector with one logo for consistency. # DMARC Source: https://docs.sendkit.dev/academy/domains/dmarc Protect your domain from email spoofing and phishing with DMARC. ## What is DMARC? DMARC (Domain-based Message Authentication, Reporting, and Conformance) is an email authentication protocol that protects your domain from being used in phishing and spoofing attacks. It works on top of two other protocols — [SPF and DKIM](/academy/domains/introduction#dns-records-explained) — and adds a crucial missing piece: **a policy that tells receiving mail servers what to do when an email fails authentication**. Without DMARC, a failed SPF or DKIM check is just a signal. The receiving server decides on its own what to do — it might deliver the email, send it to spam, or reject it. With DMARC, you explicitly define the rules. ## Why does DMARC matter? Anyone can send an email that appears to come from your domain. This is called **spoofing**, and it's how most phishing attacks work. A spoofed email might look like it's from `billing@acme.com`, but it was actually sent by a malicious actor. DMARC prevents this by: 1. **Authenticating emails** — checking that the email passes SPF or DKIM 2. **Enforcing a policy** — telling receiving servers to reject or quarantine emails that fail 3. **Sending reports** — giving you visibility into who is sending emails using your domain ## How DMARC works When a receiving mail server gets an email from your domain, it: 1. Checks if the email passes **SPF** (is the sending server authorized?) 2. Checks if the email passes **DKIM** (is the signature valid?) 3. Checks **alignment** — does the domain in the "From" header match the domain used in SPF/DKIM? 4. Looks up your **DMARC policy** to decide what to do if the checks fail The receiving server runs SPF and DKIM checks. If at least one check passes **and** the domain is aligned — the email is **delivered**. The DMARC policy is applied: `p=none` delivers anyway (monitor only), `p=quarantine` sends to spam, `p=reject` blocks the email entirely. ## Implementing DMARC ### Step 1: Start with monitoring Begin with a `p=none` policy. This tells receiving servers to deliver all emails regardless of authentication results, but send you reports so you can see what's happening. Add this TXT record to your DNS: | Field | Value | | --------- | ---------------------------------------------------- | | **Type** | TXT | | **Name** | `_dmarc.yourdomain.com` | | **Value** | `v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com;` | | **TTL** | 3600 | The `rua` tag specifies where aggregate reports are sent. These reports show which servers are sending emails using your domain and whether they pass authentication. Stay on `p=none` for at least 2–4 weeks. Review the reports to make sure all your legitimate email sources (SendKit, your own servers, marketing tools, etc.) are passing SPF and DKIM. ### Step 2: Move to quarantine Once you're confident that all legitimate emails pass authentication, tighten the policy to `p=quarantine`. Emails that fail DMARC will be sent to the recipient's spam folder. ``` v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com; ``` You can use the `pct` tag to roll this out gradually. For example, `pct=20` applies the quarantine policy to only 20% of failing emails: ``` v=DMARC1; p=quarantine; pct=20; rua=mailto:dmarc@yourdomain.com; ``` Increase the percentage over time as you gain confidence. ### Step 3: Enforce with reject The final step is `p=reject`. Emails that fail DMARC are blocked entirely — they never reach the recipient. ``` v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; ``` This is the strongest level of protection. It completely prevents anyone from spoofing your domain. Only move to `p=reject` when you are certain that all legitimate email sources for your domain are properly authenticated. A misconfigured reject policy will cause legitimate emails to be blocked. ## DMARC record parameters | Parameter | Required | Description | | --------- | -------- | -------------------------------------------------------------------------------- | | `v` | Yes | Version. Always `DMARC1` | | `p` | Yes | Policy for the domain: `none`, `quarantine`, or `reject` | | `sp` | No | Policy for subdomains. Defaults to the `p` value if not set | | `pct` | No | Percentage of failing emails to apply the policy to (1–100). Default: `100` | | `rua` | No | Email address to receive aggregate reports (e.g., `mailto:dmarc@yourdomain.com`) | | `ruf` | No | Email address to receive forensic (failure) reports | | `adkim` | No | DKIM alignment mode: `r` (relaxed, default) or `s` (strict) | | `aspf` | No | SPF alignment mode: `r` (relaxed, default) or `s` (strict) | ## Verifying your DMARC record After adding the DNS record, you can verify it's working by checking the email headers of a test email. Look for the `Authentication-Results` header: ``` Authentication-Results: mx.google.com; dkim=pass header.d=acme.com; spf=pass (google.com: domain of hello@send.acme.com designates ... as permitted sender); dmarc=pass (p=REJECT sp=REJECT) header.from=acme.com ``` The `dmarc=pass` result confirms that your DMARC record is active and the email passed all checks. ## FAQ No. DMARC is optional for domain verification. However, we strongly recommend it. Without DMARC, anyone can spoof your domain, and some email providers may treat your emails with less trust. Yes. The `rua` tag is optional. But without reports, you won't have visibility into who is sending emails using your domain, making it harder to detect spoofing or misconfigured services. **Relaxed alignment** (default) allows subdomains to pass. For example, an email from `mail.acme.com` passes DKIM alignment for `acme.com`. **Strict alignment** requires an exact match — `mail.acme.com` would fail alignment for `acme.com`. Relaxed is recommended for most setups. At least 2–4 weeks. This gives you enough data to identify all legitimate email sources for your domain. If you have many services sending email on your behalf, you may need longer. # Introduction Source: https://docs.sendkit.dev/academy/domains/introduction Learn how domains work in email sending and why they matter for deliverability. ## What is a domain? A domain is the part of an email address that comes after the `@` symbol. For example, in `hello@acme.com`, the domain is `acme.com`. When you send emails through SendKit, you need to prove that you own the domain you're sending from. This process is called **domain verification**. It prevents anyone from sending emails pretending to be you. ## Why do you need to verify a domain? Email providers like Gmail, Outlook, and Yahoo don't trust emails by default. They check whether the sender is authorized to use the domain in the "From" address. Without verification, your emails are likely to end up in spam — or be rejected entirely. When you verify a domain in SendKit, you add DNS records that tell the world: 1. **"SendKit is allowed to send emails for this domain"** — this is what SPF does 2. **"These emails really came from us and haven't been tampered with"** — this is what DKIM does 3. **"Here's what to do with emails that fail these checks"** — this is what DMARC does ## DNS records explained DNS (Domain Name System) is like a phonebook for the internet. It translates domain names into instructions that computers can understand. When you verify a domain, you're adding entries to this phonebook that vouch for SendKit as a legitimate sender. SendKit generates 4 DNS records for each domain: ### SPF (Sender Policy Framework) SPF is a TXT record that lists which mail servers are authorized to send emails for your domain. When a recipient's mail server receives an email from your domain, it checks the SPF record to see if the sending server is on the list. Without SPF, anyone could send emails claiming to be from your domain. | Field | Value | | --------- | ----------------------------------- | | **Type** | TXT | | **Name** | `send.yourdomain.com` | | **Value** | Provided on your domain detail page | | **TTL** | 3600 | ### DKIM (DomainKeys Identified Mail) DKIM adds a digital signature to every email you send. The recipient's mail server uses a public key (published in your DNS) to verify that the email content hasn't been changed in transit. Think of it like a wax seal on a letter — it proves the message is authentic and hasn't been opened. | Field | Value | | --------- | ------------------------------------- | | **Type** | TXT | | **Name** | `sendkit._domainkey.yourdomain.com` | | **Value** | `v=DKIM1; k=rsa; p=` | | **TTL** | 3600 | The DKIM public key is unique to your domain and generated automatically by SendKit. Copy the full value from the domain detail page. ### MX (Mail Exchange) The MX record on the `send` subdomain tells mail servers where to deliver bounce notifications and complaint feedback. This is how SendKit knows when an email bounces or when a recipient marks your email as spam. | Field | Value | | ------------ | ----------------------------------- | | **Type** | MX | | **Name** | `send.yourdomain.com` | | **Value** | Provided on your domain detail page | | **Priority** | 10 | | **TTL** | 3600 | ### DMARC (Domain-based Message Authentication, Reporting, and Conformance) DMARC ties SPF and DKIM together and tells receiving servers what to do when an email fails authentication. It's optional for verification, but strongly recommended. Learn more in the [DMARC guide](/academy/domains/dmarc). | Field | Value | | --------- | ----------------------- | | **Type** | TXT | | **Name** | `_dmarc.yourdomain.com` | | **Value** | `v=DMARC1; p=none;` | | **TTL** | 3600 | ## Domain verification in SendKit Go to **Domains** in the sidebar and click **Add Domain**. Enter your domain name (e.g., `acme.com`) and select a [region](/academy/domains/regions). SendKit generates 4 DNS records. Add them at your DNS provider (Cloudflare, Route 53, GoDaddy, etc.). See the [DNS provider guides](/knowledge-base/cloudflare) for step-by-step instructions. Click **Refresh** on the domain detail page. Verification usually completes within minutes, but DNS propagation can take up to a few hours. ### Verification statuses | Status | Meaning | | ---------------------- | ---------------------------------------------------------- | | **Not started** | Domain was just added, no verification attempted yet | | **Pending** | DNS records detected but still propagating | | **Verified** | All required records confirmed — you can send emails | | **Partially verified** | Some records verified, but not all required ones | | **Failed** | Required records not found or incorrect | | **Temporary failure** | A transient issue occurred — will be retried automatically | SendKit automatically checks pending domains on a schedule: * **First 2 hours** — every 10 minutes * **2–12 hours** — every 30 minutes * **12–72 hours** — every 60 minutes After 72 hours, automatic checks stop. You can always verify manually. ## Subdomains You can verify a subdomain instead of your root domain. For example, `mail.acme.com` or `notifications.acme.com`. This is useful if: * You want to separate transactional emails from marketing emails * You already have SPF/DKIM configured on your root domain for another service * You want to isolate sender reputation between different types of email Each subdomain has its own DNS records, verification status, and sender reputation. ## Next steps Choose where your emails are sent from. Protect your domain from spoofing. Display your logo in recipients' inboxes. # Regions Source: https://docs.sendkit.dev/academy/domains/regions Choose the region where your emails are sent from to reduce latency and meet data requirements. ## What are regions? When you add a domain in SendKit, you choose a **region** — the geographic location of the infrastructure that sends your emails. The region determines where your email traffic originates from. Choosing the right region can reduce latency, improve delivery speed, and help you meet data residency requirements. ## Available regions SendKit currently supports three regions: | Region | Location | Identifier | | ---------------------- | ------------------- | -------------- | | 🇧🇷 **South America** | Sao Paulo, Brazil | `sa-east-1` | | 🇺🇸 **North America** | Ohio, United States | `us-east-2` | | 🇪🇺 **Europe** | Frankfurt, Germany | `eu-central-1` | ## How to choose a region The best region is the one **closest to your recipients**. Email delivery involves multiple network hops between SendKit's servers and the recipient's mail server. A shorter distance means lower latency and faster delivery. **Examples:** * If most of your users are in Brazil or Latin America, choose 🇧🇷 **Sao Paulo (sa-east-1)** * If most of your users are in the United States or Canada, choose 🇺🇸 **United States (us-east-2)** * If most of your users are in Europe, choose 🇪🇺 **Europe (eu-central-1)** * If your users are spread globally, choose the region where the majority of them are located The region you choose affects where emails **originate from**, not where your account data is stored. ## Setting a region You select a region when adding a domain. This is a one-time choice — **the region cannot be changed after the domain is created**. If you need to switch a domain to a different region: 1. Remove all senders associated with the domain 2. Delete the domain 3. Re-add the domain with the new region 4. Update the DNS records at your provider (they will be different) 5. Verify the domain again ## Multi-region setup If you need to send emails from multiple regions using the same root domain, use **subdomains**. Each subdomain can be assigned to a different region. For example: | Subdomain | Region | Use case | | ------------- | ------------------------------ | ------------------------------ | | `us.acme.com` | 🇺🇸 United States (us-east-2) | Emails to North American users | | `br.acme.com` | 🇧🇷 Sao Paulo (sa-east-1) | Emails to Latin American users | | `eu.acme.com` | 🇪🇺 Europe (eu-central-1) | Emails to European users | Each subdomain operates independently with its own DNS records, verification status, and [warmup schedule](/knowledge-base/domain-warmup). ## Data residency The region controls where your email sending infrastructure is located. This means the email content passes through servers in that region before being delivered. If your organization has data residency requirements (e.g., data must not leave a specific country or region), choose the region that meets those requirements. Account-level data such as your team settings, API keys, and contact lists are stored independently of the sending region. ## FAQ No. The region is set when you add the domain and cannot be changed. You need to delete the domain and re-add it with the new region. The region itself doesn't affect whether emails land in the inbox or spam. However, choosing a region closer to your recipients reduces latency and can improve delivery speed. Yes. We plan to add more regions over time. If you need a specific region, let us know. # Email Headers Source: https://docs.sendkit.dev/academy/email-concepts/email-headers Learn what email headers are, how to read them, and what they tell you about an email's journey. ## What are email headers? Every email has two parts: the **headers** and the **body**. The body is the content you see — the message, images, and links. The headers are metadata attached to the email that describe where it came from, how it got to you, and whether it passed authentication checks. Headers are like a shipping label on a package. The recipient doesn't usually look at them, but they contain all the routing and verification information. ## How to view email headers ### Gmail 1. Open the email 2. Click the three dots menu (top right) 3. Click **Show original** ### Outlook 1. Open the email 2. Click **File** > **Properties** 3. Headers are in the **Internet headers** box ### Apple Mail 1. Open the email 2. Click **View** > **Message** > **All Headers** ## Key headers ### From The visible sender address. This is what the recipient sees in their inbox. ``` From: SendKit ``` The `From` header can be spoofed — anyone can set it to any address. This is why authentication protocols (SPF, DKIM, DMARC) exist. ### To The recipient's address. ``` To: paulo@acme.com ``` ### Subject The email subject line. ``` Subject: Your API key is ready ``` ### Date When the email was sent. ``` Date: Mon, 14 Mar 2026 10:32:00 -0300 ``` ### Message-ID A unique identifier for the email. No two emails should have the same Message-ID. ``` Message-ID: ``` ### Reply-To The address that receives replies. Can be different from the `From` address. ``` Reply-To: support@acme.com ``` ### Return-Path The envelope sender — where bounce notifications are sent. This is what [SPF](/academy/authentication/spf) checks against (not the `From` header). ``` Return-Path: ``` ### Received The most important header for debugging. Each mail server that handles the email adds a `Received` header. They're read **bottom to top** — the bottom one is the first server, the top one is the last. ``` Received: from send.acme.com (send.acme.com [1.2.3.4]) by mx.google.com with ESMTPS id abc123 for ; Mon, 14 Mar 2026 10:32:05 -0300 ``` This tells you: * **from** — the sending server (`send.acme.com`) * **by** — the receiving server (`mx.google.com`) * **with ESMTPS** — the connection used TLS encryption * **for** — the recipient * **timestamp** — when this hop occurred ### Authentication-Results Added by the recipient's mail server. Shows the results of SPF, DKIM, and DMARC checks. ``` Authentication-Results: mx.google.com; dkim=pass header.d=acme.com header.s=sendkit; spf=pass (google.com: domain of bounces@send.acme.com designates 1.2.3.4 as permitted sender); dmarc=pass (p=REJECT sp=REJECT) header.from=acme.com ``` This is the header to check when debugging deliverability issues. ### DKIM-Signature The [DKIM](/academy/authentication/dkim) signature added by the sending server. ``` DKIM-Signature: v=1; a=rsa-sha256; d=acme.com; s=sendkit; h=from:to:subject:date; bh=abc123...; b=xyz789... ``` ### List-Unsubscribe Tells email clients how to let the recipient unsubscribe. Gmail and other providers show an "Unsubscribe" link next to the sender name when this header is present. ``` List-Unsubscribe: , List-Unsubscribe-Post: List-Unsubscribe=One-Click ``` ## Reading headers for debugging When debugging delivery issues, focus on these headers in order: ### 1. Authentication-Results Are SPF, DKIM, and DMARC all passing? If any show `fail`, that's likely your problem. ### 2. Received headers Read bottom to top. Check the timestamps to find delays. If there's a large gap between two `Received` headers, that hop is where the delay occurred. ### 3. X-Spam headers Some providers add headers indicating spam scoring: ``` X-Spam-Status: No, score=-1.2 X-Spam-Flag: NO ``` A negative score is good. A positive score means the filter found suspicious signals. ### 4. DKIM-Signature If DKIM is failing, verify the `d=` (domain) and `s=` (selector) values match your DNS record. ## FAQ Some headers can be set by the sender (`From`, `Reply-To`, `Subject`). But headers added by receiving servers (`Received`, `Authentication-Results`) are trustworthy because they're added after the email is received. This is why authentication checks are important — they verify the headers that the sender controls. Each mail server that processes the email adds its own `Received` header. An email typically passes through 2–4 servers: the sending server, possibly an intermediary, and the recipient's server(s). Each hop adds a header. **ESMTPS** means the connection used TLS encryption. **ESMTP** means no encryption. In the `Received` header, this tells you whether that hop was encrypted. # Feedback Loops Source: https://docs.sendkit.dev/academy/email-concepts/feedback-loops Learn how email providers report spam complaints back to senders through feedback loops. ## What is a feedback loop? A feedback loop (FBL) is a system that email providers use to notify senders when a recipient marks their email as spam. When someone clicks the "Report spam" button in Gmail, Outlook, or Yahoo, the email provider sends a complaint notification back to the sender. This notification lets you know that a specific recipient considers your email unwanted — so you can stop sending to them. ## How feedback loops work The email is delivered to `recipient@gmail.com`. The recipient marks your email as spam in Gmail. A complaint in ARF (Abuse Reporting Format) is sent to the address registered for your domain. The email is marked as "complained", the recipient is added to the suppression list, and the `email.complained` webhook fires. ## ARF format Feedback loop complaints are sent in **ARF (Abuse Reporting Format)**, a standard format defined in RFC 5965. An ARF message contains: * The original email (or a portion of it) * The type of complaint (usually "abuse") * The complaining recipient's address * The date of the complaint ## Provider-specific feedback loops Each email provider implements feedback loops differently: ### Gmail Gmail uses a **header-based feedback loop**. Instead of sending ARF messages, Gmail looks for a `Feedback-ID` header in your emails and provides aggregate complaint data through Google Postmaster Tools. For individual complaints, Gmail reports through the [MX record](/academy/authentication/mx-records) you configured on your `send` subdomain. ### Outlook/Hotmail Microsoft operates the **Junk Email Reporting Program (JMRP)**. It sends ARF reports when Outlook users mark emails as junk. Reports are sent to the address associated with the sending IP or domain. ### Yahoo Yahoo has its own **Complaint Feedback Loop (CFL)**. It sends ARF reports to registered senders when Yahoo Mail users report spam. ## SendKit and feedback loops SendKit handles feedback loops automatically. When you verify a domain and add the required [MX record](/academy/authentication/mx-records), complaint notifications are routed to SendKit. When a complaint is received: 1. **The email is marked as complained** in your dashboard 2. **The `email.complained` webhook fires** so your application can react 3. **The recipient is added to the suppression list** — future sends are blocked You don't need to register with individual providers or parse ARF messages yourself. ## Why complaints matter Complaint rate is one of the most important [sender reputation](/academy/deliverability/sender-reputation) signals. Email providers track the percentage of your emails that generate complaints: | Complaint rate | Status | Action | | -------------- | -------------- | -------------------------------------------------- | | \< 0.1% | Healthy | Normal operations | | 0.1–0.5% | Warning | Investigate and improve | | > 0.5% | Sending paused | SendKit automatically pauses sending for your team | SendKit evaluates complaint rates in real time. If your complaint rate exceeds **0.5%** (with a minimum of 200 emails in the last 24 hours), sending is automatically paused. Google's own threshold is stricter — a complaint rate above **0.1%** can result in your emails being filtered to spam. A single campaign with a high complaint rate can damage your reputation for weeks. ## Reducing complaints ### Send to people who want your emails The number one cause of complaints is sending to people who didn't ask for your emails or don't remember signing up. Use double opt-in for marketing emails and make sure recipients recognize your brand. ### Make unsubscribing easy If recipients can't find the unsubscribe link, they'll use the "Report spam" button instead. Both result in the recipient being removed from your list, but a complaint damages your reputation while an unsubscribe does not. * Include a visible unsubscribe link in every marketing email * Use the `List-Unsubscribe` header (SendKit adds this automatically for campaigns) * Process unsubscribes immediately ### Set expectations at signup Tell recipients what kind of emails they'll receive and how often. "Weekly product updates" sets clear expectations. Surprises generate complaints. ### Segment your sending Not everyone on your list wants the same emails. A user who signed up for product notifications doesn't want promotional offers. Segment your list and send relevant content to each segment. ## Complaint vs unsubscribe | Action | What happens | Impact on reputation | | --------------- | --------------------------------- | ----------------------------- | | **Unsubscribe** | Recipient clicks unsubscribe link | None — this is normal | | **Complaint** | Recipient clicks "Report spam" | Negative — counts against you | You want recipients to unsubscribe (if they want to leave) rather than complain. The difference is entirely about whether they use your unsubscribe link or the spam button. ## FAQ Yes. SendKit tracks complaints per email. You can see complained emails in your dashboard and receive real-time notifications via the `email.complained` webhook. Absolutely not. Sending another email to someone who complained will generate another complaint and further damage your reputation. The recipient has clearly indicated they don't want your emails — respect that. No. Once a complaint is recorded by the email provider, it counts against your reputation. The recipient is automatically suppressed in SendKit. Focus on preventing future complaints rather than trying to reverse them. # Return-Path Source: https://docs.sendkit.dev/academy/email-concepts/return-path Learn what the Return-Path is and how it relates to bounces and SPF authentication. ## What is the Return-Path? The Return-Path (also called the envelope sender, bounce address, or MAIL FROM) is the email address where bounce notifications are sent when an email can't be delivered. It's a hidden header — recipients don't see it, but mail servers use it for routing bounce messages. It's separate from the `From` header that recipients see in their inbox. ## Return-Path vs From | Header | Who sees it | Purpose | Example | | --------------- | ----------------- | -------------------------------- | ----------------------- | | **From** | The recipient | Displays the sender in the inbox | `hello@acme.com` | | **Return-Path** | Mail servers only | Receives bounce notifications | `bounces@send.acme.com` | These are often different addresses. When you send through SendKit, the `From` address is your sender (e.g., `hello@acme.com`), but the Return-Path is set to a SendKit address on the `send` subdomain so we can process bounces for you. ## How it works The email has `From: hello@acme.com` and `Return-Path: bounces@send.acme.com`. If delivery succeeds, the process is complete. The bounce notification is sent to the Return-Path address: `bounces@send.acme.com`. The email is marked as bounced, the `email.bounced` webhook fires, and the address is added to the suppression list (if hard bounce). ## Return-Path and SPF SPF authentication checks the **Return-Path domain**, not the `From` domain. This is an important distinction. When SendKit sends an email from `hello@acme.com` with a Return-Path of `bounces@send.acme.com`, the receiving server checks the SPF record of `send.acme.com` — not `acme.com`. This is why SendKit asks you to add the SPF record on the `send` subdomain: | Header checked | Domain checked | DNS record location | | ------------------------------------ | --------------- | --------------------------------- | | Return-Path: `bounces@send.acme.com` | `send.acme.com` | SPF TXT record on `send.acme.com` | And why DMARC's **alignment** check matters — it verifies that the Return-Path domain and the `From` domain are related. Since `send.acme.com` is a subdomain of `acme.com`, relaxed alignment passes. ## Custom Return-Path By default, SendKit uses the `send` subdomain for the Return-Path (e.g., `bounces@send.acme.com`). This is automatically configured when you verify your domain. The `send` subdomain was chosen because: * It clearly identifies the purpose (sending email) * It keeps bounce handling separate from your main email * It doesn't interfere with your root domain's email configuration ## Why the Return-Path matters ### 1. Bounce processing Without a proper Return-Path, bounce notifications have nowhere to go. You'd lose visibility into delivery failures, and your list would accumulate invalid addresses — destroying your reputation over time. ### 2. SPF alignment SPF checks the Return-Path domain. If the Return-Path domain doesn't have an SPF record or it doesn't include the sending server, SPF fails. ### 3. DMARC alignment DMARC checks that the Return-Path domain (SPF) or DKIM domain aligns with the `From` domain. For SPF alignment, the Return-Path domain must match or be a subdomain of the `From` domain. ## FAQ The Return-Path subdomain is `send` by default when you verify a domain in SendKit. This is configured automatically when you add the required DNS records. This is normal and expected when using an email service like SendKit. The Return-Path is set to a SendKit-managed address so that bounce notifications are routed to SendKit for processing. DMARC alignment ensures the two domains are related (via subdomain matching). No. The Return-Path is part of the email's hidden headers. Recipients only see the `From` address. Some email clients let you view full headers (which includes the Return-Path), but this is not shown by default. # Suppression Lists Source: https://docs.sendkit.dev/academy/email-concepts/suppression-lists Understand what suppression lists are and why they're critical for email sending. ## What is a suppression list? A suppression list is a list of email addresses that should **never** receive emails from you. When you attempt to send an email to a suppressed address, the email service blocks the send before it leaves the server. Suppression lists exist to protect your sender reputation and to respect recipients who don't want your emails. ## Why suppression lists exist Sending emails to addresses that have previously bounced, complained, or unsubscribed causes real damage: | What you send to | What happens | | -------------------- | ------------------------------------------------------- | | Hard-bounced address | Increases bounce rate, signals poor list hygiene | | Complained address | Generates another complaint, further damages reputation | | Unsubscribed address | Violates regulations (CAN-SPAM, GDPR, LGPD) | Email providers track all of these signals. Repeatedly sending to suppressed addresses tells them you're either not maintaining your list or intentionally ignoring negative signals — both of which destroy trust. ## How suppression works in SendKit SendKit maintains a suppression list for each team. Addresses are added automatically when: | Event | Auto-suppressed? | Reason | | --------------------------- | ---------------- | --------------------------------------------- | | **Hard bounce** | Yes | Address is permanently invalid | | **Complaint** (spam report) | Yes | Recipient explicitly reported your email | | **Manual addition** | Yes | You added the address to the suppression list | When you try to send to a suppressed address, SendKit blocks the send and returns an error: ```json theme={null} { "name": "validation_error", "message": "The recipient email address is suppressed." } ``` The email never leaves SendKit's servers. It doesn't count against your sending quota or affect your metrics. ## Types of suppression ### Bounce suppression When an email hard bounces (address doesn't exist, domain doesn't exist), the address is automatically suppressed. This prevents you from repeatedly hitting invalid addresses and driving up your bounce rate. ### Complaint suppression When a recipient marks your email as spam, the address is automatically suppressed. This prevents you from sending more emails to someone who clearly doesn't want them — which would generate more complaints. ### Manual suppression You can manually add addresses to your suppression list. Use this when: * A recipient asks to be removed outside of the normal unsubscribe flow * You know an address is invalid or problematic * You're cleaning your list proactively ## Managing your suppression list You can view and manage your suppression list from the SendKit dashboard or via the API: * **View suppressed addresses** — see all suppressed addresses and the reason they were suppressed * **Add addresses** — manually suppress an address * **Remove addresses** — unsuppress an address (use with caution) ### Removing an address from the suppression list You can remove a suppressed address, but do so carefully: * **Bounced addresses** — only remove if you've confirmed the address is now valid (e.g., the recipient reached out to say their mailbox was fixed) * **Complained addresses** — only remove if the recipient explicitly asks to receive your emails again * **Manually added** — remove when the reason for suppression no longer applies Removing addresses from the suppression list and sending to them again without proper justification will hurt your reputation. If the address bounces or the recipient complains again, the damage is doubled. ## Suppression list vs unsubscribe list These are related but distinct: | List | Purpose | Scope | | -------------------- | -------------------------------------- | ----------------------------------------------------- | | **Suppression list** | Block all email delivery to an address | All emails — transactional and marketing | | **Unsubscribe list** | Remove from marketing emails | Marketing emails only — transactional still delivered | A suppressed address receives **nothing**. An unsubscribed address receives no marketing emails but still gets transactional emails (password resets, receipts, etc.). ## Best practices ### Never circumvent the suppression list If you export your contacts and re-import them, the suppression list still applies. SendKit checks every send against the suppression list regardless of how the recipient was added. ### Don't remove bounced addresses without verification "Maybe the address works now" is not a valid reason to unsuppress. Verify first — ideally by having the recipient contact you directly. ### Import existing suppressions If you're migrating from another email service, import your existing suppression list into SendKit. This prevents you from sending to addresses that already bounced or complained on your previous service. ### Monitor suppression growth A rapidly growing suppression list can indicate problems: * **Many bounces** — your list has hygiene issues * **Many complaints** — your content or targeting needs improvement * **Both** — stop and reassess your email strategy ## FAQ Yes. A suppressed address is blocked from receiving any email — transactional or marketing. If a user needs to receive transactional emails (like password resets) but was suppressed due to a complaint, you'll need to remove them from the suppression list. Yes. The suppression list is per team in SendKit. All members of your team share the same suppression list. SendKit skips suppressed addresses in the batch and delivers to the rest. The suppressed sends are not counted against your quota. You won't receive an error for the batch as a whole — individual suppressed addresses are silently skipped. # Transactional vs Marketing Email Source: https://docs.sendkit.dev/academy/email-concepts/transactional-vs-marketing Understand the difference between transactional and marketing emails and why it matters. ## What's the difference? **Transactional emails** are triggered by a user's action and contain information they expect to receive. They're one-to-one and time-sensitive. **Marketing emails** are sent to a group of recipients to promote something. They're one-to-many and not triggered by a specific user action. The distinction matters for deliverability, compliance, and how you should handle each type. ## Transactional emails Transactional emails are sent in response to something the user did. The recipient expects them — they're part of the product experience. **Examples:** * Password reset emails * Email verification / confirmation * Order confirmations and receipts * Shipping notifications * Account activity alerts (login from new device, payment failed) * Two-factor authentication codes * Invoice and billing emails * Invitation emails (team invites, shared documents) **Key characteristics:** * Triggered by user action * Sent to one recipient at a time * Time-sensitive (a password reset link that arrives 2 hours late is useless) * Expected by the recipient * Don't require an unsubscribe link (but compliance varies by jurisdiction) * Typically have very high open rates (60–80%) ## Marketing emails Marketing emails are sent proactively by the business to a list of recipients. The goal is to inform, engage, or sell. **Examples:** * Newsletters * Product announcements * Promotional offers and discounts * Event invitations * Re-engagement campaigns ("We miss you!") * Educational content / drip campaigns **Key characteristics:** * Sent to a group of recipients * Not triggered by a specific user action * Require explicit opt-in consent * **Must** include an unsubscribe link (legally required) * Typically have lower open rates (15–30%) * Subject to stricter spam filtering ## Why you should separate them Sending transactional and marketing emails from the same domain and infrastructure creates a risk: if your marketing emails generate complaints or bounces (which is more likely), the reputation damage spills over to your transactional emails. A password reset email going to spam because your last newsletter had a high complaint rate is a bad user experience. ### Use separate subdomains The most common approach is to use different subdomains: | Type | Subdomain | Example | | ------------- | --------------- | ------------------------- | | Transactional | `send.acme.com` | Password resets, receipts | | Marketing | `mail.acme.com` | Newsletters, promotions | Each subdomain has its own sender reputation. If marketing reputation degrades, transactional emails are unaffected. ### Use separate senders Within SendKit, create different [senders](/knowledge-base/senders) for each type: | Sender | Use | | ----------------------- | ---------------------------------------- | | `noreply@send.acme.com` | Transactional (password resets, alerts) | | `hello@send.acme.com` | Transactional (welcome emails, receipts) | | `news@mail.acme.com` | Marketing (newsletters) | | `offers@mail.acme.com` | Marketing (promotions) | ## Deliverability differences Email providers treat these types differently: | Factor | Transactional | Marketing | | --------------------------- | ------------------------------------------------ | -------------------------- | | **Spam filtering** | More lenient — providers know users expect these | Stricter — higher scrutiny | | **Gmail tabs** | Usually lands in Primary | Often lands in Promotions | | **Engagement expectations** | High opens expected | Lower opens tolerated | | **Complaint tolerance** | Very low — any complaints are a red flag | Slightly higher tolerance | | **Delivery priority** | Higher — time-sensitive | Lower — not urgent | ## Compliance differences ### Unsubscribe requirements * **Transactional:** Generally exempt from unsubscribe requirements in CAN-SPAM and GDPR, because they're necessary for the service the user signed up for * **Marketing:** Must include a working unsubscribe link. This is legally required in CAN-SPAM, GDPR, LGPD, and most other jurisdictions ### Consent requirements * **Transactional:** Implied consent — the user signed up for your service and expects operational emails * **Marketing:** Explicit consent required — the user must actively opt in to receive marketing emails Don't abuse the transactional exemption by adding marketing content to transactional emails. A password reset email with a promotional banner at the bottom is still a marketing email in the eyes of regulators and spam filters. ## The gray area Some emails don't fit neatly into either category: | Email | Type? | Reasoning | | ----------------------------------- | ------------- | ----------------------------------------------------- | | Welcome email after signup | Transactional | Triggered by user action, expected | | Onboarding series (tips, tutorials) | Gray area | Related to user action but promotional in nature | | Usage report / weekly summary | Transactional | User-specific, informational | | "Your trial is expiring" | Transactional | Account-related, time-sensitive | | "Check out our new feature" | Marketing | Not triggered by user action, promotional | | Review/feedback request | Gray area | Related to a purchase but not transactional in nature | When in doubt, treat it as marketing. It's safer from both a compliance and deliverability perspective. ## FAQ Yes. SendKit handles both transactional and marketing emails. We recommend using separate subdomains and senders for each type to protect your transactional deliverability. Under CAN-SPAM (US), transactional emails are exempt from the unsubscribe requirement. Under GDPR (EU) and LGPD (Brazil), the rules are more nuanced — operational emails necessary for the service are generally exempt, but you should consult legal advice for your specific case. Transactional emails should have open rates of 60%+ (often higher). If yours are low, check: (1) Are they landing in spam? Check authentication. (2) Are they actually transactional? If they're disguised marketing, recipients may ignore them. (3) Are your subject lines clear and descriptive? # TLS Source: https://docs.sendkit.dev/academy/security/tls Learn how TLS encrypts email in transit and the difference between opportunistic and enforced modes. ## What is TLS? TLS (Transport Layer Security) is a protocol that encrypts the connection between two mail servers when transferring an email. It ensures that the email content can't be read or tampered with by anyone intercepting the traffic between the sender and recipient's servers. TLS protects emails **in transit** — while they're being transmitted from one server to another. It does not encrypt the email at rest (stored on the server). ## How TLS works in email When SendKit sends an email to a recipient's mail server, the two servers perform a **TLS handshake**: SendKit's server connects to the recipient's mail server and announces TLS support. The recipient's server confirms TLS support and sends its certificate. SendKit verifies the certificate is valid and trusted. Both servers agree on encryption parameters and establish a secure channel. The email is transmitted over the encrypted connection. Anyone intercepting the traffic sees only encrypted data. Once the encrypted connection is established, the email is transmitted securely. Anyone intercepting the traffic would see encrypted data instead of the email content. ## TLS modes in SendKit SendKit supports two TLS modes per domain, configurable from the **Configuration** tab on your domain detail page: ### Opportunistic TLS (default) SendKit **attempts** a TLS connection. If the recipient's server supports TLS, the email is sent encrypted. If it doesn't, the email falls back to an unencrypted connection. | Recipient supports TLS | What happens | | ---------------------- | ---------------------- | | Yes | Email sent encrypted | | No | Email sent unencrypted | This is the default and recommended mode for most senders. It maximizes deliverability while encrypting whenever possible. The vast majority of mail servers today support TLS — Gmail, Outlook, Yahoo, and most business email providers all do. ### Enforced TLS SendKit **requires** a TLS connection. If the recipient's server doesn't support TLS, the email is **not sent** and returns an error. | Recipient supports TLS | What happens | | ---------------------- | ------------------------------ | | Yes | Email sent encrypted | | No | Email rejected — not delivered | Use enforced TLS when you have strict security requirements and would rather not deliver an email than send it unencrypted. This is common in healthcare, finance, and other regulated industries. Enforced TLS means some recipients may not receive your emails if their mail server doesn't support TLS. Most major providers support TLS, but some older or smaller mail servers do not. ## TLS versions TLS has gone through several versions: | Version | Status | | ------- | ------------------------------- | | TLS 1.0 | Deprecated — insecure | | TLS 1.1 | Deprecated — insecure | | TLS 1.2 | Widely supported, secure | | TLS 1.3 | Latest, most secure and fastest | SendKit supports TLS 1.2 and TLS 1.3. The version used depends on what the recipient's server supports — SendKit always negotiates the highest available version. ## MTA-STS MTA-STS (Mail Transfer Agent Strict Transport Security) is a standard that lets a domain declare that it supports TLS and that sending servers should refuse to deliver email without encryption. It's similar to HSTS for websites — it prevents downgrade attacks where an attacker forces an unencrypted connection. If a recipient's domain publishes an MTA-STS policy, SendKit respects it and will only deliver over TLS, regardless of your domain's TLS mode setting. ## DANE DANE (DNS-based Authentication of Named Entities) is another standard for securing email transport. It uses DNSSEC to publish the recipient server's TLS certificate in DNS, preventing man-in-the-middle attacks even if a certificate authority is compromised. DANE is less widely deployed than MTA-STS but provides stronger guarantees. SendKit supports DANE when the recipient's domain has it configured. ## Checking TLS in email headers You can verify that TLS was used by checking the email headers. Look for the `Received` header: ``` Received: from send.acme.com (send.acme.com [1.2.3.4]) by mx.google.com with ESMTPS id abc123 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384) ``` The `ESMTPS` indicates TLS was used (vs `ESMTP` for unencrypted). The version and cipher suite are also shown. ## FAQ No. TLS encrypts emails **in transit** between servers. Once the email arrives at the recipient's server, it's decrypted and stored. The recipient's email provider (and potentially their administrator) can read it. For end-to-end encryption, you'd need something like PGP or S/MIME, which are not related to TLS. For most senders, opportunistic TLS is the right choice. It encrypts when possible without risking delivery failures. Use enforced TLS only if your compliance or security requirements mandate that no email be sent unencrypted, and you accept that some recipients may not receive your emails. The vast majority. Google reports that over 95% of inbound email to Gmail is encrypted with TLS. Major providers like Outlook, Yahoo, and iCloud all support TLS. The remaining percentage is mostly small, self-hosted, or legacy mail servers. # Antigravity Source: https://docs.sendkit.dev/ai/antigravity Connect SendKit to Google Antigravity for AI-powered email management [Antigravity](https://antigravity.google) is Google's AI coding agent. You can connect it to SendKit's MCP server to manage your email infrastructure with natural language. ## Prerequisites * Antigravity installed * A SendKit API key with **Full** permission ## Setup Edit your Antigravity MCP configuration file and add the SendKit server: ```json theme={null} { "mcpServers": { "sendkit": { "serverUrl": "https://mcp.sendkit.dev/sendkit", "headers": { "Authorization": "Bearer sk_your_api_key_here" } } } } ``` Replace `sk_your_api_key_here` with your actual API key from the [SendKit dashboard](https://app.sendkit.dev). Restart Antigravity to load the new MCP configuration. Ask Antigravity to interact with your SendKit account: ``` List all my SendKit domains ``` Antigravity uses `"serverUrl"` for remote MCP connections (not `"url"`). This is the same format used by Windsurf. ## Example prompts ``` Send a test email from hello@mydomain.com to test@example.com ``` ``` Create a new contact list called "Early Adopters" ``` ``` Show me my email sending reputation ``` # Claude Code Source: https://docs.sendkit.dev/ai/claude-code Connect SendKit to Claude Code for AI-powered email management from the terminal [Claude Code](https://docs.anthropic.com/en/docs/claude-code) is Anthropic's CLI tool for working with Claude directly in your terminal. You can connect it to SendKit's MCP server to manage your email infrastructure with natural language. ## Prerequisites * Claude Code installed (`npm install -g @anthropic-ai/claude-code`) * A SendKit API key with **Full** permission ## Setup Run the following command in your terminal: ```bash theme={null} claude mcp add --transport http sendkit https://mcp.sendkit.dev/sendkit \ --header "Authorization: Bearer sk_your_api_key_here" ``` Replace `sk_your_api_key_here` with your actual API key from the [SendKit dashboard](https://app.sendkit.dev). This adds the server to your project's `.mcp.json` file. To add it globally instead, append the `--scope user` flag. Start Claude Code and ask it to interact with your SendKit account: ```bash theme={null} claude ``` ``` List all my SendKit domains ``` ## Manual configuration You can also configure the server manually by creating a `.mcp.json` file in your project root: ```json theme={null} { "mcpServers": { "sendkit": { "type": "http", "url": "https://mcp.sendkit.dev/sendkit", "headers": { "Authorization": "Bearer sk_your_api_key_here" } } } } ``` For global configuration, add the same to `~/.claude.json`. ## Example prompts Once connected, you can use natural language to manage your SendKit account: ``` Create a sender called "Support" with username "support" on my verified domain ``` ``` Show me all contacts that are subscribed to the "Newsletter" list ``` ``` Send a test email from support@mydomain.com to test@example.com with subject "Hello" ``` ``` What's my sending reputation right now? ``` # Claude Desktop Source: https://docs.sendkit.dev/ai/claude-desktop Connect SendKit to the Claude Desktop app for AI-powered email management [Claude Desktop](https://claude.ai/download) is Anthropic's desktop application for chatting with Claude. You can connect it to SendKit's MCP server to manage your email infrastructure through conversation. ## Prerequisites * Claude Desktop installed * A SendKit API key with **Full** permission ## Setup In Claude Desktop, go to **Settings** > **Integrations** and click **Add custom connector**. Enter the following server URL: ``` https://mcp.sendkit.dev/sendkit ``` When prompted for authentication, provide your API key as a Bearer token. Start a new conversation and ask Claude to interact with your SendKit account: ``` List all my SendKit domains ``` You should see Claude use the SendKit tools to fetch your domain list. ## Example prompts ``` Show me my email sending metrics for the last 7 days ``` ``` Create a new contact list called "Beta Users" ``` ``` Add test@example.com to the suppression list ``` ``` Delete the API key named "old-key" ``` # OpenAI Codex Source: https://docs.sendkit.dev/ai/codex Connect SendKit to OpenAI Codex CLI for AI-powered email management [OpenAI Codex](https://github.com/openai/codex) is OpenAI's CLI agent for software development. You can connect it to SendKit's MCP server to manage your email infrastructure with natural language. ## Prerequisites * Codex CLI installed (`npm install -g @openai/codex`) * A SendKit API key with **Full** permission ## Setup Add your SendKit API key to your shell profile (`~/.zshrc`, `~/.bashrc`, etc.): ```bash theme={null} export SENDKIT_API_KEY="sk_your_api_key_here" ``` Replace `sk_your_api_key_here` with your actual API key from the [SendKit dashboard](https://app.sendkit.dev). Edit `~/.codex/config.toml` and add the SendKit server: ```toml theme={null} [mcp_servers.sendkit] url = "https://mcp.sendkit.dev/sendkit" bearer_token_env_var = "SENDKIT_API_KEY" ``` Close and reopen Codex to load the new configuration. Ask Codex to interact with your SendKit account: ``` List all my SendKit domains ``` Codex uses TOML for configuration (not JSON). It provides `bearer_token_env_var` to securely reference API keys from environment variables instead of hardcoding them in the config file. ## Example prompts ``` Send a test email from support@mydomain.com to test@example.com ``` ``` Create a segment called "Active Users" filtering emails containing @company.com ``` ``` Show me all contacts on the "Newsletter" list ``` # Cursor Source: https://docs.sendkit.dev/ai/cursor Connect SendKit to Cursor for AI-powered email management in your editor [Cursor](https://cursor.com) is an AI-powered code editor. You can connect it to SendKit's MCP server to manage your email infrastructure directly from the editor. ## Prerequisites * Cursor editor installed * A SendKit API key with **Full** permission ## Setup In your project root, create or edit `.cursor/mcp.json`: ```json theme={null} { "mcpServers": { "sendkit": { "type": "http", "url": "https://mcp.sendkit.dev/sendkit", "headers": { "Authorization": "Bearer sk_your_api_key_here" } } } } ``` Replace `sk_your_api_key_here` with your actual API key from the [SendKit dashboard](https://app.sendkit.dev). Restart Cursor to load the new MCP configuration. Open the AI chat panel and ask: ``` List all my SendKit senders ``` ## Example prompts Use Cursor's AI chat or inline editing to interact with SendKit: ``` Create a sender called "Notifications" with username "notifications" on domain example.com ``` ``` Show me all my email templates ``` ``` What's my bounce rate in the last 24 hours? ``` # Gemini CLI Source: https://docs.sendkit.dev/ai/gemini-cli Connect SendKit to Gemini CLI for AI-powered email management from the terminal [Gemini CLI](https://github.com/google-gemini/gemini-cli) is Google's command-line AI assistant. You can connect it to SendKit's MCP server to manage your email infrastructure with natural language. ## Prerequisites * Gemini CLI installed * A SendKit API key with **Full** permission ## Setup Edit your Gemini CLI settings at `~/.gemini/settings.json`: ```json theme={null} { "mcpServers": { "sendkit": { "httpUrl": "https://mcp.sendkit.dev/sendkit", "headers": { "Authorization": "Bearer sk_your_api_key_here" } } } } ``` Replace `sk_your_api_key_here` with your actual API key from the [SendKit dashboard](https://app.sendkit.dev). For project-level configuration, create `.gemini/settings.json` in your project root instead. Close and reopen Gemini CLI to load the new configuration. Ask Gemini to interact with your SendKit account: ``` List all my SendKit senders ``` Gemini CLI uses `"httpUrl"` for HTTP streaming servers (not `"url"`). The `"url"` field is used for SSE transport only. ## Example prompts ``` Create a new contact list called "Beta Users" ``` ``` What's my sending reputation right now? ``` ``` Validate the email address user@example.com ``` # GitHub Copilot Source: https://docs.sendkit.dev/ai/github-copilot Connect SendKit to GitHub Copilot in VS Code for AI-powered email management [GitHub Copilot](https://github.com/features/copilot) supports MCP servers in agent mode, allowing you to connect SendKit directly to your VS Code workflow. ## Prerequisites * VS Code with GitHub Copilot extension installed * Copilot agent mode enabled * A SendKit API key with **Full** permission ## Setup In your project root, create or edit `.vscode/mcp.json`: ```json theme={null} { "servers": { "sendkit": { "type": "http", "url": "https://mcp.sendkit.dev/sendkit", "headers": { "Authorization": "Bearer sk_your_api_key_here" } } } } ``` Replace `sk_your_api_key_here` with your actual API key from the [SendKit dashboard](https://app.sendkit.dev). Reload the window or restart VS Code to load the MCP configuration. Open Copilot Chat in agent mode and ask: ``` List all my SendKit domains ``` You should see Copilot use the SendKit tools to fetch your data. VS Code uses `"servers"` as the top-level key (not `"mcpServers"`). This is different from most other MCP clients. ## Global configuration To make SendKit available across all projects, use the command palette and run **MCP: Open User Configuration** to add the server to your user-level settings. ## Example prompts ``` Create a sender called "Notifications" with username "notifications" on my domain ``` ``` Show me all my email templates ``` ``` What's my bounce rate in the last 24 hours? ``` # Introduction Source: https://docs.sendkit.dev/ai/introduction Connect AI coding assistants to your SendKit account using the Model Context Protocol SendKit provides a built-in [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that lets AI coding assistants manage your email infrastructure directly. Your AI assistant can create domains, manage contacts, send emails, and more — all through natural language. ## What is MCP? MCP is an open protocol that connects AI assistants to external tools and data sources. Instead of copying and pasting API calls, your AI assistant can interact with SendKit directly. ## Available tools SendKit exposes 60 tools across 13 categories: | Category | Tools | Description | | ---------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | **Emails** | List, Get, Send, Validate | List and inspect sent emails, send transactional emails, and validate addresses | | **Domains** | List, Get, Create, Update, Delete, Verify | Manage sending domains and DNS verification | | **Automations** | List, Get, Create, Update, Delete | Manage email automations and workflows | | **Campaigns** | List, Get, Create, Update, Delete | Manage email marketing campaigns | | **Senders** | List, Get, Create, Update, Delete | Manage sender identities | | **Templates** | List, Get, Create, Update, Delete | Manage email templates | | **Contacts** | List, Get, Create, Update, Delete, Add to lists, Remove from list, Get lists | Full contact management | | **Lists** | List, Get, Create, Update, Delete | Manage contact lists | | **Properties** | List, Create, Update, Delete | Manage custom contact properties | | **Segments** | List, Get, Create, Update, Delete | Manage contact segments with filters | | **Suppressions** | List, Create, Delete | Manage the suppression list | | **API Keys** | List, Create, Delete | Manage API keys | | **Metrics** | Get Metrics, Get Reputation | Sending metrics and reputation status | ## How it works Create an API key from the [SendKit dashboard](https://app.sendkit.dev). You need a **Full** permission key. Add the SendKit MCP server to your assistant's configuration using the server URL and your API key. Ask your assistant to manage your SendKit account. For example: "Create a new sender called Support on my domain" or "List all contacts subscribed to the newsletter list." ## Server URL ``` https://mcp.sendkit.dev/sendkit ``` Authentication uses the same API keys as the REST API, passed as a Bearer token. ## Next steps CLI assistant by Anthropic. Desktop app by Anthropic. AI-powered code editor. Editor with Cascade AI. VS Code with MCP extensions. Copilot agent mode. CLI assistant by Google. Open-source CLI assistant. CLI agent by OpenAI. AI agent by Google. # OpenCode Source: https://docs.sendkit.dev/ai/opencode Connect SendKit to OpenCode for AI-powered email management from the terminal [OpenCode](https://github.com/opencode-ai/opencode) is an open-source AI coding assistant that runs in your terminal. You can connect it to SendKit's MCP server to manage your email infrastructure with natural language. ## Prerequisites * OpenCode installed * A SendKit API key with **Full** permission ## Setup Edit your OpenCode configuration at `.opencode.json` in your project root (or `~/.opencode.json` for global config): ```json theme={null} { "mcpServers": { "sendkit": { "type": "sse", "url": "https://mcp.sendkit.dev/sendkit", "headers": { "Authorization": "Bearer sk_your_api_key_here" } } } } ``` Replace `sk_your_api_key_here` with your actual API key from the [SendKit dashboard](https://app.sendkit.dev). Close and reopen OpenCode to load the new MCP configuration. Ask OpenCode to interact with your SendKit account: ``` List all my SendKit domains ``` OpenCode currently supports `stdio` and `sse` transports. The `sse` transport is used for remote HTTP servers. ## Example prompts ``` Create a sender called "Support" with username "support" on my verified domain ``` ``` Show me my email sending metrics for the last 7 days ``` ``` Add user@example.com to the suppression list ``` # Tools reference Source: https://docs.sendkit.dev/ai/tools-reference Complete reference of all SendKit MCP tools available to your AI assistant This page lists every tool available through the SendKit MCP server. Your AI assistant can call any of these tools to manage your SendKit account. MCP tool names use kebab-case with a `-tool` suffix. For example, the **ListEmails** tool is registered as `list-emails-tool` in MCP. ## Emails | Tool | Description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListEmails** | List sent emails with pagination. Returns each email's recipient, subject, delivery status (sent, delivered, opened, clicked, bounced, complained, failed), domain, and timestamps. Filterable by recipient email, status, domain, and date range. Defaults to the last 14 days. | | **GetEmail** | Get a sent email's full details by ID, including recipient, subject, HTML and text content, delivery status, associated domain and template, and a timeline of delivery events (sent, delivered, opened, clicked, bounced, etc.). | | **SendEmail** | Send a transactional email immediately or schedule it for later. Requires a verified sender (from), recipient (to), subject, and at least HTML or plain text content. Supports CC, BCC, reply-to, custom tags, and scheduled sending. | | **ValidateEmail** | Validate an email address by checking syntax, DNS, mailbox existence, disposable domain, role address, and random input detection. Consumes one validation credit per call. Returns a recommendation on whether to block the address. | ## Domains | Tool | Description | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListDomains** | List all sending domains for the current team. Returns each domain's name, verification status, DNS records (DKIM, SPF, DMARC), tracking settings, TLS mode, and region. | | **GetDomain** | Get a sending domain's full details by ID, including verification status, DNS records (DKIM, SPF, DMARC) that need to be configured, tracking settings, and TLS mode. | | **CreateDomain** | Register a new sending domain. After creation, DNS records (DKIM, SPF, DMARC) must be configured at the domain's DNS provider before the domain can be verified and used for sending emails. | | **UpdateDomain** | Update a sending domain's open tracking, click tracking, or TLS mode (opportunistic or enforced). Domain name and region cannot be changed after creation. | | **DeleteDomain** | Delete a sending domain. All senders associated with this domain must be removed first or the operation will fail. | | **VerifyDomain** | Trigger DNS verification for a domain. Checks that the required DKIM, SPF, and DMARC records have been properly configured at the domain's DNS provider. The domain must be verified before it can be used for sending. | ## Senders | Tool | Description | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **ListSenders** | List all sender identities (from addresses) for the current team. Returns each sender's display name, email address, associated domain, and reply-to address. Senders are the "from" identities used when sending emails. | | **GetSender** | Get a sender identity's full details by ID, including display name, email address (username\@domain), associated domain, and reply-to address. | | **CreateSender** | Create a new sender identity (from address) for sending emails. A sender combines a display name with a username and a verified domain to form the full email address (e.g., "John \<[john@example.com](mailto:john@example.com)>"). | | **UpdateSender** | Update a sender identity's display name, email username, associated domain, or reply-to address. | | **DeleteSender** | Delete a sender identity. Fails if the sender is currently used by active campaigns or email templates. | ## Templates | Tool | Description | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListTemplates** | List all email templates for the current team. Returns each template's name, subject, sender, status (published/draft), folder ID, and content type. Searchable by name. Filterable by folder ID — use `"unassigned"` for templates without a folder. | | **GetTemplate** | Get an email template's full details by ID, including name, subject, sender, HTML and plain text content, reply-to address, status (published/draft), and folder ID. | | **CreateTemplate** | Create a new email template with HTML and/or plain text content. Requires a sender identity and subject line. Optionally assign to a folder by providing a folder ID. | | **UpdateTemplate** | Update an email template's name, subject, sender, HTML content, plain text content, reply-to address, status (published/draft), or folder assignment. | | **DeleteTemplate** | Delete an email template. Fails if the template is used by unsent campaigns (draft, scheduled, sending) or active/paused automations. Templates used only by sent campaigns can be deleted. | ## Template Folders | Tool | Description | | ------------------------ | ------------------------------------------------------------------------------------------------------------------ | | **ListTemplateFolders** | List all template folders for the current team. Returns each folder's name and template count. Searchable by name. | | **GetTemplateFolder** | Get a template folder's details by ID, including its name and template count. | | **CreateTemplateFolder** | Create a new template folder. Folder names must be unique within a team. | | **UpdateTemplateFolder** | Rename a template folder. Does not affect the templates within the folder. | | **DeleteTemplateFolder** | Delete a template folder. Templates in the folder will become unassigned, not deleted. | ## Automations | Tool | Description | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListAutomations** | List automations with pagination. Returns each automation's name, status (draft, active, paused), entry type, step count, contact count, and timestamps. Filterable by name and status. | | **GetAutomation** | Get an automation's full details by ID, including name, status, entry configuration, all workflow steps (trigger, email, delay, condition, webhook) with their configurations, edges connecting steps, and timestamps. | | **CreateAutomation** | Create a new automation in draft status. Only a name is required initially. Use the update-automation tool to configure entry type, entry target, and reentry settings. | | **UpdateAutomation** | Update a draft or paused automation: name, entry type, entry target, reentry setting, and the full workflow graph (steps and edges). Steps define the workflow nodes (trigger, email, delay, condition, webhook) with their configurations. Edges connect steps together. When steps and edges are provided, the entire workflow is replaced. | | **DeleteAutomation** | Delete an automation. Only draft or paused automations without active contacts can be deleted. | ## Campaigns | Tool | Description | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListCampaigns** | List email marketing campaigns with pagination. Returns each campaign's name, subject, status (draft, scheduled, sending, sent, partial\_sent), audience configuration, template, sender, recipient counts, and timestamps. Filter by `search` (name match), `tab` (UI grouping: `draft`, `scheduled`, `sent` — where `sent` includes `partial_sent`), or `status` (literal value, single or comma-separated). `tab` takes precedence when both are supplied. | | **GetCampaign** | Get a campaign's full details by ID, including name, subject, status (draft, scheduled, sending, sent, partial\_sent), audience type and target, associated template and sender, recipient/sent/failed counts, and scheduling timestamps. | | **CreateCampaign** | Create a new email marketing campaign in draft status. Only a name is required initially. Use the update-campaign tool to configure template, sender, audience, subject, and scheduling before sending. | | **UpdateCampaign** | Update a draft campaign's configuration: name, subject, template, sender, audience (all\_contacts, contact\_list, or segment), preview text, reply-to address, and scheduling. Only draft campaigns can be updated. | | **DeleteCampaign** | Delete a draft campaign. Only campaigns in draft status can be deleted. Campaigns that are sending, sent, or scheduled cannot be deleted. | ## Contacts | Tool | Description | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListContacts** | List contacts for the current team with pagination. Returns each contact's email, name, subscription status, list memberships, and custom properties. Use the search parameter to find contacts by email address. | | **GetContact** | Get a contact's full details by ID, including email, name, subscription status, external user ID, list memberships, and custom properties. | | **CreateContact** | Create or update (upsert) a contact by email address. If a contact with the given email already exists, it will be updated instead of creating a duplicate. Optionally assign to lists and set custom properties. | | **UpdateContact** | Update a contact's email, name, external user ID, subscription status, list memberships, or custom properties. Passing list\_ids will replace all current list memberships (use add-contact-to-lists-tool to append instead). | | **DeleteContact** | Permanently delete a contact and remove them from all lists. This action cannot be undone. | | **AddContactToLists** | Add a contact to one or more lists while preserving existing list memberships. Unlike update-contact-tool which replaces all lists, this appends to the contact's current lists. | | **RemoveContactFromList** | Remove a contact from a specific list. The contact is not deleted, only their membership in the specified list is removed. | | **GetContactLists** | Get all lists that a specific contact belongs to, with pagination. Returns list names and IDs for the given contact. | ## Lists | Tool | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **ListContactLists** | List all contact lists for the current team. Lists are used to organize contacts into groups for targeted email campaigns and automations. Supports search by list name. | | **GetContactList** | Get a contact list's details by ID, including its name and contact count. | | **CreateContactList** | Create a new contact list. Lists group contacts together for targeted email campaigns and automations. | | **UpdateContactList** | Rename a contact list. Does not affect the contacts within the list. | | **DeleteContactList** | Delete a contact list. Fails if the list is currently used by active campaigns or automations. Contacts in the list are not deleted. | ## Properties | Tool | Description | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListContactProperties** | List all custom contact properties for the current team. Properties are custom fields (string, number, or date) that can be attached to contacts for personalization and segmentation. | | **CreateContactProperty** | Create a new custom contact property. Properties are custom fields (string, number, or date) that extend contact data for personalization in emails and filtering in segments. | | **UpdateContactProperty** | Update a custom contact property's key, type (string, number, or date), or fallback value. | | **DeleteContactProperty** | Delete a custom contact property. Fails if the property is currently used in segment filter conditions. Existing contact values for this property will be removed. | ## Segments | Tool | Description | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListSegments** | List all segments for the current team. Segments are dynamic groups of contacts defined by filter conditions (e.g., "subscribed contacts who opened an email in the last 30 days"). Used to target specific audiences in campaigns. | | **GetSegment** | Get a segment's full details by ID, including its name, match type (all/any), and filter groups with conditions used to dynamically match contacts. | | **CreateSegment** | Create a new segment with filter conditions to dynamically group contacts. Filters use groups of conditions with match types (all/any) to target contacts by email activity, properties, list membership, and more. | | **UpdateSegment** | Update a segment's name and filter conditions. Replaces all existing filter groups and conditions with the provided values. | | **DeleteSegment** | Delete a segment. Fails if the segment is currently used by active campaigns or automations. | ## Suppressions | Tool | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListSuppressions** | List all suppressed email addresses for the current team. Suppressed addresses are blocked from receiving any emails, typically due to bounces, complaints, or manual addition. | | **CreateSuppression** | Add an email address to the suppression list to prevent all future emails from being sent to this address. Use this to manually block recipients who should not receive emails. | | **DeleteSuppression** | Remove an email address from the suppression list, allowing future emails to be sent to this address again. | ## API Keys | Tool | Description | | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **ListApiKeys** | List all API keys for the current team. Returns each key's name, permission level (full or send), domain restriction, expiration date, and last used timestamp. | | **CreateApiKey** | Create a new API key for the current team. Returns the plain text token which is only shown once and cannot be retrieved later. Keys can be scoped to a specific domain and given full or send-only permissions. | | **DeleteApiKey** | Permanently revoke and delete an API key. Any integrations using this key will immediately stop working. | ## Metrics | Tool | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **GetEmailMetrics** | Get email delivery and engagement metrics for a date range. Returns totals and rates for sent, delivered, opened, clicked, bounced, and complained emails, plus daily chart data. Filterable by domain. Defaults to the last 14 days. | | **GetReputation** | Get the current team's email sending reputation. Returns status (healthy, warned, or paused), bounce rate, complaint rate, and total emails sent in the last 24 hours. A paused status means sending is blocked due to high bounce or complaint rates. | # VS Code Source: https://docs.sendkit.dev/ai/vs-code Connect SendKit to VS Code with any MCP-compatible extension Visual Studio Code supports MCP servers natively. You can connect SendKit to VS Code and use it with GitHub Copilot agent mode or other MCP-compatible extensions. ## Prerequisites * VS Code installed * An MCP-compatible extension (e.g. GitHub Copilot) * A SendKit API key with **Full** permission ## Setup In your project root, create or edit `.vscode/mcp.json`: ```json theme={null} { "servers": { "sendkit": { "type": "http", "url": "https://mcp.sendkit.dev/sendkit", "headers": { "Authorization": "Bearer sk_your_api_key_here" } } } } ``` Replace `sk_your_api_key_here` with your actual API key from the [SendKit dashboard](https://app.sendkit.dev). Reload the window or restart VS Code to load the MCP configuration. Open the AI chat in agent mode and ask: ``` List all my SendKit domains ``` VS Code uses `"servers"` as the top-level key (not `"mcpServers"`). This is different from most other MCP clients. ## Global configuration To make SendKit available across all projects, use the command palette and run **MCP: Open User Configuration** to add the server to your user-level settings. # Windsurf Source: https://docs.sendkit.dev/ai/windsurf Connect SendKit to Windsurf for AI-powered email management with Cascade [Windsurf](https://windsurf.com) is an AI-powered editor with Cascade, a deep context-aware AI assistant. You can connect it to SendKit's MCP server to manage your email infrastructure. ## Prerequisites * Windsurf editor installed * A SendKit API key with **Full** permission ## Setup Edit the Windsurf MCP configuration at `~/.codeium/windsurf/mcp_config.json`: ```json theme={null} { "mcpServers": { "sendkit": { "serverUrl": "https://mcp.sendkit.dev/sendkit", "headers": { "Authorization": "Bearer sk_your_api_key_here" } } } } ``` Replace `sk_your_api_key_here` with your actual API key from the [SendKit dashboard](https://app.sendkit.dev). Restart Windsurf to load the new configuration. Open Cascade and ask: ``` List all my SendKit domains ``` ## Example prompts Use Cascade to interact with SendKit: ``` Create a new domain called notifications.example.com in us-east-1 ``` ``` Show me all contacts on the "VIP" list ``` ``` Validate the email address user@example.com ``` # Add a contact to lists Source: https://docs.sendkit.dev/api-reference/endpoint/add-contacts-to-list POST /contacts/{id}/lists Add a contact to one or more lists. Lists that the contact already belongs to will be ignored. # Create an API key Source: https://docs.sendkit.dev/api-reference/endpoint/create-api-key POST /api-keys Create a new API key. The plain-text token is only returned once in the response — store it securely. # Create a campaign Source: https://docs.sendkit.dev/api-reference/endpoint/create-campaign POST /campaigns Create a new campaign in draft status. Only a name is required initially. Use the update endpoint to configure the template, sender, audience, and other settings. # Upsert a contact Source: https://docs.sendkit.dev/api-reference/endpoint/create-contact POST /contacts Create a new contact or update an existing one if a contact with the same email already exists (upsert). You can optionally attach the contact to lists and set property values inline. # Create a domain Source: https://docs.sendkit.dev/api-reference/endpoint/create-domain POST /domains Add a new sending domain to your account. The domain will be created with DNS records that you need to configure at your DNS provider before verifying. Your account has a domain limit based on your plan. # Create a list Source: https://docs.sendkit.dev/api-reference/endpoint/create-list POST /lists Create a new contact list for your team. # Create a property Source: https://docs.sendkit.dev/api-reference/endpoint/create-property POST /properties Create a new contact property for your team. Properties define custom fields that can be set on contacts. # Create a segment Source: https://docs.sendkit.dev/api-reference/endpoint/create-segment POST /segments Create a new segment with filter conditions. Segments allow you to dynamically group contacts based on conditions. # Create a sender Source: https://docs.sendkit.dev/api-reference/endpoint/create-sender POST /senders Create a new sender identity. The sender must be associated with a verified domain that belongs to your account. # Add to suppression list Source: https://docs.sendkit.dev/api-reference/endpoint/create-suppression POST /suppressions Add an email address to the suppression list. Suppressed emails will not receive any emails. If the email already exists in the suppression list, the existing entry is returned with a `200` status code. The email is normalized to lowercase. # Create a template Source: https://docs.sendkit.dev/api-reference/endpoint/create-template POST /templates Create a new email template. Templates allow you to reuse email content and sender settings across transactional emails and campaigns. # Create a template folder Source: https://docs.sendkit.dev/api-reference/endpoint/create-template-folder POST /template-folders Create a new template folder. Folder names must be unique within your team. # Delete an API key Source: https://docs.sendkit.dev/api-reference/endpoint/delete-api-key DELETE /api-keys/{id} Permanently revoke and delete an API key. This action cannot be undone. # Delete a campaign Source: https://docs.sendkit.dev/api-reference/endpoint/delete-campaign DELETE /campaigns/{id} Delete a campaign by ID. Only draft campaigns can be deleted. # Delete a contact Source: https://docs.sendkit.dev/api-reference/endpoint/delete-contact DELETE /contacts/{id} Delete a contact by ID. This is a soft delete — the contact will no longer appear in API responses. # Delete a domain Source: https://docs.sendkit.dev/api-reference/endpoint/delete-domain DELETE /domains/{id} Delete a domain from your account. The domain must not have any active senders. All associated DNS records and provider configurations will be cleaned up. # Delete a list Source: https://docs.sendkit.dev/api-reference/endpoint/delete-list DELETE /lists/{id} Delete a contact list by ID. Contacts in the list are not deleted. # Delete a property Source: https://docs.sendkit.dev/api-reference/endpoint/delete-property DELETE /properties/{id} Delete a contact property by ID. All associated property values on contacts will also be removed. # Delete a segment Source: https://docs.sendkit.dev/api-reference/endpoint/delete-segment DELETE /segments/{id} Delete a segment by ID. Segments used by active campaigns or automations cannot be deleted. # Delete a sender Source: https://docs.sendkit.dev/api-reference/endpoint/delete-sender DELETE /senders/{id} Delete a sender from your account. The sender must not be used by any campaigns or templates. # Remove from suppression list Source: https://docs.sendkit.dev/api-reference/endpoint/delete-suppression DELETE /suppressions/{id} Remove an email address from the suppression list. This allows the email to receive emails again. # Delete a template Source: https://docs.sendkit.dev/api-reference/endpoint/delete-template DELETE /templates/{id} Delete a template by ID. Templates used by campaigns cannot be deleted. # Delete a template folder Source: https://docs.sendkit.dev/api-reference/endpoint/delete-template-folder DELETE /template-folders/{id} Delete a template folder. Templates in the folder will become unassigned, not deleted. # Get a campaign Source: https://docs.sendkit.dev/api-reference/endpoint/get-campaign GET /campaigns/{id} Retrieve a single campaign by ID, including its template, sender, and sending statistics. # Get a contact Source: https://docs.sendkit.dev/api-reference/endpoint/get-contact GET /contacts/{id} Retrieve a single contact by ID, including their lists and property values. # Get a domain Source: https://docs.sendkit.dev/api-reference/endpoint/get-domain GET /domains/{id} Retrieve a single domain by ID, including its DNS records and current verification status. # Get an email Source: https://docs.sendkit.dev/api-reference/endpoint/get-email GET /emails/{id} Retrieve a single email by ID, including its events, domain, and template details. # Get a list Source: https://docs.sendkit.dev/api-reference/endpoint/get-list GET /lists/{id} Retrieve a single contact list by ID. # Get email metrics Source: https://docs.sendkit.dev/api-reference/endpoint/get-metrics GET /metrics Returns email sending metrics including sent, delivered, opened, clicked, bounced, and complained counts with daily chart data. Supports date range and domain filtering. # Get sending reputation Source: https://docs.sendkit.dev/api-reference/endpoint/get-reputation GET /metrics/reputation Returns the current sending reputation status with bounce and complaint rates. # Get a segment Source: https://docs.sendkit.dev/api-reference/endpoint/get-segment GET /segments/{id} Retrieve a single segment by ID. # Get a sender Source: https://docs.sendkit.dev/api-reference/endpoint/get-sender GET /senders/{id} Retrieve a single sender by ID, including its associated domain. # Get a template Source: https://docs.sendkit.dev/api-reference/endpoint/get-template GET /templates/{id} Retrieve a single template by ID, including its sender and variables. # Get a template folder Source: https://docs.sendkit.dev/api-reference/endpoint/get-template-folder GET /template-folders/{id} Retrieve a template folder's details including its name and template count. # Health check Source: https://docs.sendkit.dev/api-reference/endpoint/health-check GET /health # List all API keys Source: https://docs.sendkit.dev/api-reference/endpoint/list-api-keys GET /api-keys Retrieve a paginated list of all API keys for your team. # List campaigns Source: https://docs.sendkit.dev/api-reference/endpoint/list-campaigns GET /campaigns Retrieve a paginated list of campaigns for your team. Supports filtering by name, status, or UI tab grouping. # List contacts Source: https://docs.sendkit.dev/api-reference/endpoint/list-contacts GET /contacts Retrieve a paginated list of contacts for your team. Results are ordered by creation date, newest first. # List a contact's lists Source: https://docs.sendkit.dev/api-reference/endpoint/list-contacts-in-list GET /contacts/{id}/lists Retrieve a paginated list of lists that a contact belongs to. # List domains Source: https://docs.sendkit.dev/api-reference/endpoint/list-domains GET /domains Retrieve a paginated list of all domains in your account, including their DNS records and verification status. # List emails Source: https://docs.sendkit.dev/api-reference/endpoint/list-emails GET /emails Retrieve a paginated list of emails sent by your team. Supports filtering by search term, status, domain, and date range. # List all lists Source: https://docs.sendkit.dev/api-reference/endpoint/list-lists GET /lists Retrieve a paginated list of all contact lists for your team. # List all properties Source: https://docs.sendkit.dev/api-reference/endpoint/list-properties GET /properties Retrieve a paginated list of all contact properties for your team. # List all segments Source: https://docs.sendkit.dev/api-reference/endpoint/list-segments GET /segments Retrieve a paginated list of all segments for your team. # List senders Source: https://docs.sendkit.dev/api-reference/endpoint/list-senders GET /senders Retrieve a paginated list of all senders in your account, including their associated domain. # List suppressions Source: https://docs.sendkit.dev/api-reference/endpoint/list-suppressions GET /suppressions Retrieve a paginated list of all suppressed email addresses. # List template folders Source: https://docs.sendkit.dev/api-reference/endpoint/list-template-folders GET /template-folders Retrieve a paginated list of all template folders for your team. Each folder includes a template count. # List templates Source: https://docs.sendkit.dev/api-reference/endpoint/list-templates GET /templates Retrieve a paginated list of all templates for your team. Supports filtering by name and folder. # Remove a contact from a list Source: https://docs.sendkit.dev/api-reference/endpoint/remove-contact-from-list DELETE /contacts/{id}/lists/{listId} Remove a contact from a specific list. The contact itself is not deleted. # Send bulk emails Source: https://docs.sendkit.dev/api-reference/endpoint/send-bulk-emails POST /emails/bulk Send up to 100 individual emails in a single request. Each email in the array is independent — with its own recipient, subject, content, and optional template. The request body can be either an object with an `emails` key, or a plain JSON array of email objects. Each email follows the same rules as the single send endpoint: `from`, `subject`, and `html`/`text` are required unless a template is provided. Results are returned in the same order as the input array, with each entry indicating success (with an `id`) or error (with an error message). # Send email Source: https://docs.sendkit.dev/api-reference/endpoint/send-email POST /emails Send a transactional email to a recipient. You can provide the email content directly with `html`/`text`, or reference a published template by ID. When using a template, the `from`, `subject`, `html`, `text`, and `reply_to` fields are optional and will be resolved from the template if not provided. The `from` address must belong to a verified domain in your account. # Send MIME email Source: https://docs.sendkit.dev/api-reference/endpoint/send-mime-email POST /emails/mime Send a raw MIME email. The raw message must be a valid RFC 2822 formatted email. The `envelope_from` must belong to a verified domain in your account. # Update a campaign Source: https://docs.sendkit.dev/api-reference/endpoint/update-campaign PUT /campaigns/{id} Update a campaign's settings. Only draft campaigns can be updated. You can configure the name, subject, template, sender, audience, preview text, reply-to address, and schedule. # Update a contact Source: https://docs.sendkit.dev/api-reference/endpoint/update-contact PUT /contacts/{id} Update a contact's fields. Only the provided fields will be updated. You can also sync lists and properties inline. # Update a domain Source: https://docs.sendkit.dev/api-reference/endpoint/update-domain PUT /domains/{id} Update domain settings such as open tracking, click tracking, and TLS mode. Changes to tracking options are synced with the email provider. # Update a list Source: https://docs.sendkit.dev/api-reference/endpoint/update-list PUT /lists/{id} Update a contact list's name. # Update a property Source: https://docs.sendkit.dev/api-reference/endpoint/update-property PUT /properties/{id} Update a contact property's key, type, or fallback value. # Update a segment Source: https://docs.sendkit.dev/api-reference/endpoint/update-segment PUT /segments/{id} Update a segment's name, match type, and filter conditions. # Update a sender Source: https://docs.sendkit.dev/api-reference/endpoint/update-sender PUT /senders/{id} Update sender details such as name, username, reply-to address, or domain. All fields are optional — only provided fields will be updated. # Update a template Source: https://docs.sendkit.dev/api-reference/endpoint/update-template PUT /templates/{id} Update a template's content, sender, subject, or other settings. # Update a template folder Source: https://docs.sendkit.dev/api-reference/endpoint/update-template-folder PUT /template-folders/{id} Rename a template folder. Does not affect the templates within the folder. # Validate an email address Source: https://docs.sendkit.dev/api-reference/endpoint/validate-email POST /emails/validate Validate an email address by checking syntax, DNS records, mailbox existence, and whether it is a disposable or role-based address. # Verify a domain Source: https://docs.sendkit.dev/api-reference/endpoint/verify-domain POST /domains/{id}/verify Trigger DNS verification for a domain. This checks that the required DNS records (DKIM, SPF, DMARC, MX) are properly configured. Verification runs asynchronously — poll the domain to check the updated status. # Introduction Source: https://docs.sendkit.dev/api-reference/introduction The SendKit API lets you send transactional emails with a simple REST API. ## Base URL The SendKit API is available at: ``` https://api.sendkit.dev ``` ## Authentication All API requests require a Bearer token in the `Authorization` header. You can create API keys from the [dashboard](https://app.sendkit.dev/api-keys). ```bash theme={null} Authorization: Bearer sk_your_api_key ``` Keep your API key secret. Do not expose it in client-side code or public repositories. ## Rate limiting API requests are rate limited per team based on your plan. When you exceed the limit, the API returns a `429` status code with a `Retry-After` header indicating how many seconds to wait. ### Send email — `POST /emails` | Plan | Rate limit | Monthly quota | Daily limit | | ---- | ------------- | ---------------- | ----------- | | Free | 60 req/min | 3,000 emails | 100 emails | | 10K | 120 req/min | 10,000 emails | No limit | | 25K | 120 req/min | 25,000 emails | No limit | | 50K | 300 req/min | 50,000 emails | No limit | | 75K | 300 req/min | 75,000 emails | No limit | | 100K | 600 req/min | 100,000 emails | No limit | | 150K | 600 req/min | 150,000 emails | No limit | | 250K | 600 req/min | 250,000 emails | No limit | | 500K | 1,200 req/min | 500,000 emails | No limit | | 750K | 1,200 req/min | 750,000 emails | No limit | | 1M | 1,200 req/min | 1,000,000 emails | No limit | | 2M | 1,200 req/min | 2,000,000 emails | No limit | | 5M | 1,200 req/min | 5,000,000 emails | No limit | ### Validate email — `POST /emails/validate` Fixed at **60 requests per minute** for all plans. ### Rate limit error response ```json theme={null} { "name": "rate_limit_exceeded", "message": "Rate limit exceeded. Please retry after 30 seconds." } ``` ## Errors The API uses conventional HTTP status codes. All error responses include a `name` and `message` field. | Status | Description | | ------ | ---------------------------------------------------------------- | | `200` | Success | | `202` | Accepted — request received and will be processed asynchronously | | `401` | Missing or invalid API key | | `422` | Validation error (invalid parameters, unverified domain, etc.) | | `429` | Rate limit exceeded | ```json theme={null} { "name": "validation_error", "message": "The from address domain is not verified." } ``` ### Common validation errors | Error message | Cause | | ---------------------------------------- | ----------------------------------------------------------------- | | The from address domain is not verified. | The domain in the `from` address is not verified in your account. | | Monthly email quota exceeded. | Your team has reached its monthly sending limit. | | Sending is paused for this account. | Sending has been paused for your account. Contact support. | # Introduction Source: https://docs.sendkit.dev/index SendKit is the email API for developers. SendKit provides a simple, powerful API to send transactional emails from your application. Integrate with your favorite language or framework in minutes. ## Quickstart Send emails from Node.js using the official SDK. Send emails from PHP using the official SDK. Integrate SendKit with the Laravel mail driver. Send emails from Python using the official SDK. Send emails from Ruby using the official SDK. Send emails from Go using the official SDK. Send emails from Java using the official SDK. Send emails from Rust using the official SDK. Send emails from Elixir using the official SDK. Send emails from C# and .NET using the official SDK. ## Explore Send transactional emails via the REST API. Verify your domain to start sending. Get notified about email events in real time. ## Learn Domains, DNS records, regions, and verification. SPF, DKIM, MX records, and DNS propagation. Reputation, spam filters, bounces, and throttling. TLS encryption for email in transit. Headers, return path, feedback loops, and more. CAN-SPAM, GDPR, and LGPD. # API Keys Source: https://docs.sendkit.dev/knowledge-base/api-keys Create and manage API keys to authenticate your requests to the SendKit API. ## What are API keys? API keys are how you authenticate requests to the SendKit API. Every API call requires a valid key passed as a Bearer token in the `Authorization` header. Keys are scoped to your team — any key created by a team member has access to the team's resources (emails, domains, contacts, etc.). ## Creating an API key Go to **API Keys** in the dashboard and click **Create API Key**. | Field | Required | Description | | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ | | **Name** | Yes | A label to identify the key (e.g., `Production`, `Staging`, `CI/CD`) | | **Permission** | Yes | Access level for the key. **Full access** grants access to all API endpoints. **Send only** restricts the key to sending emails only | | **Domain** | No | Optionally scope the key to a specific verified domain. When set, the key can only send emails from this domain | | **Expiration** | No | Optional expiration date. After this date, the key stops working | After creation, the full key is shown **once**. Copy it immediately — you won't be able to see it again. SendKit stores a hash of your API key, not the key itself. If you lose it, you'll need to create a new one. ## Key format All SendKit API keys follow the format: ``` sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` Keys start with `sk_` followed by 48 random characters (51 characters total). ## Using your API key Pass the key as a Bearer token in the `Authorization` header on every API request. See the [API Reference](/api-reference/introduction) for examples and interactive testing. For the [Laravel SDK](/sdks/laravel), just set the `SENDKIT_API_KEY` environment variable and you're ready to go. ## Expiration API keys can be created with or without an expiration date: * **No expiration** — The key remains active until you delete it * **With expiration** — The key automatically becomes inactive after the set date. Requests made with an expired key return a `401` error Expired keys are not deleted — they stay visible in the dashboard so you can track usage history. You can delete them manually when no longer needed. ## Security best practices Create different keys for production, staging, and development. If a key is compromised, you only need to rotate one. If you're sharing a key with a contractor or CI/CD pipeline, set an expiration date so it automatically stops working. Store keys in environment variables or secret managers. Never hardcode them in your codebase. Create a new key, update your application, then delete the old one. SendKit tracks `last used at` so you can verify the old key is no longer in use before deleting it. ## Deleting an API key You can delete an API key at any time from the dashboard. Deletion is **immediate and irreversible** — any application still using the key will start receiving `401` errors. Check the **Last used** column before deleting to make sure the key isn't actively in use. ## FAQ There's no limit. Create as many keys as you need for different environments, services, or team members. No. The full key is only shown once at creation time. SendKit stores a secure hash, not the original key. If you lose it, create a new one. Yes. API keys belong to the team, not individual users. Any key created by a team member can be used to access the team's resources. The API returns a `401 Unauthorized` error. Create a new key or remove the expiration from the existing one. # Apple Private Relay Source: https://docs.sendkit.dev/knowledge-base/apple-private-relay How to send emails to @privaterelay.appleid.com addresses and prevent bounces. ## What is Apple Private Relay? Apple's Private Email Relay lets users who sign in with Apple hide their real email address. Instead of sharing their personal email, they get a unique address like `abc123@privaterelay.appleid.com` that forwards to their real inbox. These are real, deliverable email addresses — not disposable or temporary emails. However, emails will bounce unless your sending domain is registered with Apple. This applies specifically to **Sign in with Apple's** Hide My Email feature. It is separate from iCloud+'s Hide My Email, which is a broader privacy feature available since iOS 15 that generates random addresses for any context, not just app sign-ins. ## Why emails bounce If you're seeing bounces when sending to `@privaterelay.appleid.com` addresses, it's likely because Apple doesn't recognize your sending domain. Other common reasons include: * The user deleted their Hide My Email address from their Apple settings * The user exceeded their daily limit of 100 emails for that relay address * Your domain's SPF or DKIM records are misconfigured or missing * Your sender email address is not registered with Apple ## How to fix bounces Go to the [Apple Developer Portal](https://developer.apple.com) and navigate to **Certificates, Identifiers & Profiles** → **Services** → **Sign in with Apple for Email Communication** → **Configure**. Click the **+** button in the Email Sources section and register your sending domain (e.g., `acme.com`) and its MAIL FROM subdomain (e.g., `send.acme.com`). You can enter multiple domains as a comma-separated list. You must register and validate **every** domain and subdomain you send from, including return-path domains. In the same Email Sources section, add all email addresses you send from (e.g., `hello@acme.com`, `support@acme.com`). If you don't own a domain configured for email, you can register individual sender email addresses instead. Apple requires all outbound emails to be authenticated with **SPF** and/or **DKIM**. If you've already verified your domain in SendKit, your SPF and DKIM records are already in place — no extra DNS configuration is needed. ## Registration limits Apple enforces limits on the number of email sources you can register: | Account type | Maximum email sources | | -------------------- | --------------------- | | Individual developer | 32 | | Organization | 100 | An email source can be either a domain or an individual email address. ## Bounce notifications You can receive notifications when emails fail to deliver through the relay. In the Apple Developer Portal, account owners and admins can enable delivery failure notifications under the Sign in with Apple for Email Communication settings. ## Important notes * Only the app that the user authorized via "Sign in with Apple" has permission to send to their relay address. * After registering domains, allow a few minutes for Apple to process the changes before retesting. * Bounced relay addresses should be handled like any other bounce — don't keep retrying delivery to addresses that consistently fail. ## Resources * [Apple Developer — Configure Private Email Relay Service](https://developer.apple.com/help/account/capabilities/configure-private-email-relay-service/) * [Apple Developer — Communicating Using the Private Email Relay Service](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js/communicating_using_the_private_email_relay_service) # Automations Source: https://docs.sendkit.dev/knowledge-base/automations Build automated email workflows that trigger based on contact activity and run on autopilot. ## What are automations? Automations are multi-step workflows that send emails, wait, check conditions, and call webhooks — all triggered automatically when contacts enter through a list or segment. Once active, they run on autopilot without any manual intervention. ## Automation lifecycle | Status | Description | | ---------- | -------------------------------------------------------------------------- | | **Draft** | Being built. You can add, edit, and remove steps freely | | **Active** | Running. Contacts are being enrolled and processed | | **Paused** | Temporarily stopped. No new contacts are enrolled and processing is halted | You can only edit an automation's workflow when it's in **Draft** status. Active automations must be paused first. ## Building a workflow Automations use a visual graph-based builder. You connect steps together to define the flow contacts go through. ### Step types The entry point. Defines how contacts enter the automation — via a contact list or a segment. Sends an email using a template. Supports personalization with contact variables and properties. Pauses the contact for a set amount of time before moving to the next step. Configurable in minutes, hours, or days. Splits the flow based on whether a contact meets a condition. Creates **Yes** and **No** branches. Sends an HTTP request to an external URL when a contact reaches this step. ### Trigger (entry point) Every automation starts with a trigger that defines how contacts enter: | Entry type | How it works | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Contact list** | Contacts are enrolled automatically when they're added to a specific [list](/knowledge-base/lists-and-segments). Event-driven — happens in real time. | | **Segment** | Contacts are enrolled when they match a [segment's](/knowledge-base/lists-and-segments) filter conditions. Checked periodically via scheduled polling. | ### Email steps Email steps send a message using one of your templates. The template's subject, sender, and body are used, with personalization variables replaced per contact. All the same [personalization variables](/knowledge-base/campaigns#personalization) from campaigns are available — `{{FIRST_NAME}}`, `{{EMAIL}}`, custom properties, etc. ### Delay steps Delay steps pause the contact's progression through the workflow. You configure: * **Duration** — A numeric value * **Unit** — Minutes, Hours, or Days For example, a delay of `3 Days` means the contact waits 3 days before moving to the next step. ### Condition steps Conditions check whether a contact meets a specific criteria and split the flow into two branches: * **Yes branch** — Contact meets the condition * **No branch** — Contact does not meet the condition **Available conditions:** | Condition | What it checks | | ---------------------------- | ------------------------------------------------------------------- | | **Email Opened** | Whether the contact opened a specific email step | | **Email Not Opened** | Whether the contact has not opened a specific email step | | **Email Clicked** | Whether the contact clicked a link in a specific email step | | **Email Not Clicked** | Whether the contact has not clicked a link in a specific email step | | **Email Bounced** | Whether a specific email step bounced for the contact | | **Has Completed Automation** | Whether the contact has completed a specific automation | | **Is Active In Automation** | Whether the contact is currently active in a specific automation | | **In List** | Whether the contact belongs to a specific list | | **Not In List** | Whether the contact does not belong to a specific list | | **In Segment** | Whether the contact matches a specific segment | | **Contact Property** | Whether a contact's property matches a given value | This lets you build responsive workflows — for example, send a follow-up only to contacts who didn't open your first email. ## Contact enrollment When a contact enters an automation, they're tracked individually through each step. You can see: | Status | Meaning | | ------------- | ---------------------------------------------- | | **Active** | Currently progressing through the workflow | | **Completed** | Reached the end of the workflow | | **Exited** | Left the automation early (e.g., unsubscribed) | | **Failed** | A step failed during processing | ### Re-entry By default, a contact can only go through an automation once. You can enable **Allow re-entry** to let contacts be enrolled again if they match the trigger conditions a second time. ## Example workflow Here's a typical onboarding automation: A contact is added to your "New Users" list (via API, import, or manually). Immediately sends a welcome email with getting started instructions. Waits 2 days before the next step. Checks if the contact opened the welcome email. * **Yes** — Sends an advanced tips email * **No** — Resends the welcome email with a different subject line ## Sending limits Like [campaigns](/knowledge-base/campaigns), automations respect your account's sending limits: * **[Domain warmup](/knowledge-base/domain-warmup)** — Emails are paused if your daily warmup limit is reached * **Daily limit (Free plan)** — Free plan accounts are limited to 100 emails per day * **Monthly quota** — Your plan's monthly email limit is enforced ## FAQ No. You must pause the automation first, which moves it back to a state where you can modify the workflow. Contacts already in progress will resume when you reactivate. They stay at their current step. When you reactivate, they continue from where they left off. Yes. Automations are independent — a contact can be enrolled in as many as they qualify for. They exit the automation immediately. No further emails are sent. Each step is processed individually per contact. Emails are dispatched as soon as a contact reaches an email step (after any delays). # Bluehost Source: https://docs.sendkit.dev/knowledge-base/bluehost Learn how to verify your domain on SendKit using Bluehost DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Bluehost account](https://my.bluehost.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Bluehost, go to **Domains**, click your domain, then select **DNS**. Click **Add Record** for each of the following. ### 1. DKIM record Click **Add Record** and select **TXT** as the type. In the **Host Record** field, enter `sendkit._domainkey`. In the **TXT Value** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as the default and click **Save**. | Bluehost field | SendKit value | | -------------- | ---------------------------- | | Type | `TXT` | | Host Record | `sendkit._domainkey` | | TXT Value | Your DKIM value from SendKit | ### 2. SPF record Click **Add Record** and select **TXT**. In the **Host Record** field, enter `send`. In the **TXT Value** field, paste the SPF value from your SendKit domain detail page. Leave TTL as the default and click **Save**. | Bluehost field | SendKit value | | -------------- | --------------------------- | | Type | `TXT` | | Host Record | `send` | | TXT Value | Your SPF value from SendKit | ### 3. MX record Click **Add Record** and select **MX**. In the **Host Record** field, enter `send`. In the **Points To** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as the default and click **Save**. | Bluehost field | SendKit value | | -------------- | -------------------------- | | Type | `MX` | | Host Record | `send` | | Points To | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Click **Add Record** and select **TXT**. In the **Host Record** field, enter `_dmarc`. In the **TXT Value** field, enter `v=DMARC1; p=none;`. Leave TTL as the default and click **Save**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Bluehost DNS changes can take up to 30 minutes to propagate. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting If you're on the new Bluehost dashboard, go to **Domains > My Domains**, click **Manage** next to your domain, then select the **DNS** tab. The layout may vary between the classic and new dashboard. If your domain points to nameservers other than Bluehost's, you need to manage DNS at that provider. Check your nameserver settings in the domain overview. # Campaigns Source: https://docs.sendkit.dev/knowledge-base/campaigns Send marketing emails to your audience with targeted campaigns. ## What are campaigns? Campaigns let you send the same email to a group of contacts — your entire list, a specific list, or a dynamic segment. They're built for marketing and promotional emails like newsletters, product updates, and announcements. ## Campaign lifecycle Every campaign goes through a clear set of statuses: | Status | Description | | ---------------- | ------------------------------------------------------------------ | | **Draft** | Being configured. You can edit, preview, and test | | **Scheduled** | Set to send at a specific date and time | | **Sending** | Currently processing and delivering emails | | **Sent** | All emails have been delivered | | **Partial sent** | Some emails were sent before a limit was reached (warmup or quota) | ## Creating a campaign Give it an internal name to identify it in the dashboard (recipients don't see this). Select an email template for the campaign body. The template's subject and sender are auto-filled but can be overridden. Choose who receives the campaign: * **All contacts** — Every subscribed contact in your team * **Contact list** — A specific list you've created * **Segment** — A dynamic group based on filter conditions Send immediately or pick a date and time for scheduled delivery. ## Audience targeting You have three options for choosing recipients: | Audience type | How it works | | ---------------- | ---------------------------------------------------------------------------------------------- | | **All contacts** | Sends to every contact in your team | | **Contact list** | Sends to contacts in a specific [list](/knowledge-base/lists-and-segments) | | **Segment** | Sends to contacts matching a [segment's](/knowledge-base/lists-and-segments) filter conditions | In all cases, SendKit automatically excludes: * **Unsubscribed contacts** — Contacts who opted out of marketing emails * **Suppressed addresses** — Addresses on your [suppression list](/knowledge-base/suppression-list) (bounces, complaints) ## Personalization Campaigns support dynamic variables that are replaced with each contact's data when the email is sent: | Variable | Replaced with | | ---------------- | ---------------------------- | | `{{FIRST_NAME}}` | Contact's first name | | `{{LAST_NAME}}` | Contact's last name | | `{{FULL_NAME}}` | First and last name combined | | `{{EMAIL}}` | Contact's email address | | `{{USER_ID}}` | Contact's user ID | Custom [properties](/knowledge-base/properties) are also available as variables. If a variable isn't set for a contact, the property's fallback value is used. Variables work in the **subject line**, **preview text**, and **template body**. ## Scheduling Set a `scheduled_at` date and time to send the campaign later. The campaign status changes to **Scheduled** and SendKit automatically sends it at the specified time. You can cancel a scheduled campaign at any time before it starts sending — it reverts back to **Draft** status. ## Sending limits Campaigns respect your account's sending limits: * **[Domain warmup](/knowledge-base/domain-warmup)** — If your domain is still warming up, the campaign pauses when the daily limit is reached. The status becomes **Partial sent**. * **Daily limit (Free plan)** — Free plan accounts are limited to 100 emails per day. The campaign pauses when this limit is reached. * **Monthly quota** — Your plan's monthly email limit is enforced. The campaign stops if the quota is exceeded. If a campaign is partially sent due to limits, the remaining contacts won't receive the email automatically. You may need to create a new campaign for the remaining audience after limits reset. ## Campaign analytics After sending, the campaign detail page shows real-time stats: | Metric | What it tracks | | -------------- | ----------------------------------------- | | **Recipients** | Total emails created for the campaign | | **Sent** | Emails successfully accepted for delivery | | **Delivered** | Emails confirmed delivered to inbox | | **Opened** | Recipients who opened the email | | **Clicked** | Recipients who clicked a link | | **Failed** | Emails that permanently failed | You can also browse individual email deliveries with their status and event history. ## FAQ No. Only campaigns in **Draft** status can be edited. Once a campaign is scheduled or sent, its configuration is locked. No. Only **Draft** campaigns can be deleted. Sent campaigns are preserved for analytics and history. Contacts are checked at processing time. If they unsubscribe before their email is processed, they won't receive it. No. Each campaign is sent once. To resend to the same audience, create a new campaign with the same template. Campaigns are processed in chunks of 500 contacts. Each email is dispatched individually with rate limiting to protect your sender reputation. # Cloudflare Source: https://docs.sendkit.dev/knowledge-base/cloudflare Learn how to verify your domain on SendKit using Cloudflare DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Cloudflare dashboard](https://dash.cloudflare.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to your Cloudflare dashboard, select your domain, and go to **DNS > Records**. Click **Add record** for each of the following. ### 1. DKIM record Click **Add record** and select **TXT** as the type. In the **Name** field, enter `sendkit._domainkey` (Cloudflare automatically appends your domain). In the **Content** field, paste the full DKIM value from your SendKit domain detail page. It starts with `v=DKIM1; k=rsa; p=...`. Leave TTL as **Auto** and click **Save**. | Cloudflare field | SendKit value | | ---------------- | ---------------------------- | | Type | `TXT` | | Name | `sendkit._domainkey` | | Content | Your DKIM value from SendKit | | TTL | Auto | ### 2. SPF record Click **Add record** and select **TXT** as the type. In the **Name** field, enter `send` (Cloudflare automatically appends your domain, making it `send.yourdomain.com`). In the **Content** field, paste the SPF value from your SendKit domain detail page. Leave TTL as **Auto** and click **Save**. | Cloudflare field | SendKit value | | ---------------- | --------------------------- | | Type | `TXT` | | Name | `send` | | Content | Your SPF value from SendKit | | TTL | Auto | ### 3. MX record Click **Add record** and select **MX** as the type. In the **Name** field, enter `send`. In the **Mail server** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as **Auto** and click **Save**. | Cloudflare field | SendKit value | | ---------------- | -------------------------- | | Type | `MX` | | Name | `send` | | Mail server | Your MX value from SendKit | | Priority | `10` | | TTL | Auto | ### 4. DMARC record (optional) Click **Add record** and select **TXT** as the type. In the **Name** field, enter `_dmarc`. In the **Content** field, enter `v=DMARC1; p=none;`. Leave TTL as **Auto** and click **Save**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Cloudflare DNS typically propagates within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Cloudflare's orange cloud proxy does **not** apply to TXT or MX records — only to A/AAAA/CNAME records. Your DNS records will work regardless of proxy settings. Some Cloudflare interfaces may truncate long TXT values when displaying them, but the full value is stored correctly. Copy the value directly from SendKit and paste it — don't try to re-type it. The SendKit SPF record goes on the `send` subdomain, not your root domain. It won't conflict with any existing SPF record on `yourdomain.com`. # Contacts Source: https://docs.sendkit.dev/knowledge-base/contacts Manage your recipients with SendKit's contact system — automatic or manual. ## What are contacts? Contacts are the people you send emails to. Every recipient in SendKit is stored as a contact with their email address and optional profile information. You can create contacts manually, via the [API](/api-reference/endpoint/create-contact), or let SendKit do it automatically. ## Automatic contact creation Every time you send an email through SendKit — via API, campaign, or automation — the recipients (to, cc, bcc) are **automatically saved as contacts**. You don't need to import or pre-register them. This means your contact list is always up to date with everyone you've ever emailed. If a contact with the same email already exists, SendKit skips creation. Emails are normalized to lowercase to prevent duplicates. ## Contact fields Every contact has the following built-in fields: | Field | Required | Description | | -------------- | -------- | ------------------------------------------------------------------- | | **Email** | Yes | The contact's email address (unique per team) | | **First name** | No | First name | | **Last name** | No | Last name | | **User ID** | No | An external identifier to link the contact to a user in your system | | **Subscribed** | Auto | Whether the contact is subscribed to marketing emails | Need more fields? Use [Properties](/knowledge-base/properties) to add custom attributes like company name, plan type, or signup date. ## Subscription status Each contact has a subscription toggle. Unsubscribed contacts are excluded from marketing campaigns but can still receive transactional emails via the API. You can toggle subscription status from the contact detail page or via the [API](/api-reference/endpoint/update-contact). ## Organizing contacts SendKit gives you two ways to group contacts: * **[Lists](/knowledge-base/lists-and-segments)** — Static groups you manage manually. Add or remove contacts explicitly. * **[Segments](/knowledge-base/lists-and-segments)** — Dynamic groups based on filters. Contacts are included automatically when they match your conditions. Learn more in [Lists & Segments](/knowledge-base/lists-and-segments). ## Deleting contacts Contacts are soft-deleted — they're removed from your active contact list but the data is preserved. This ensures email delivery history and analytics remain intact. ## FAQ No. SendKit automatically creates contacts from your email recipients. You can also create them manually or via the API if you want to set up contacts before sending. Yes. Contacts belong to the team, not individual users. All team members see the same contact list. SendKit uses the existing contact — it doesn't create a duplicate. Email addresses are unique per team. Yes. Use [Properties](/knowledge-base/properties) to define custom attributes with different types (text, number, date) and optional fallback values. # DigitalOcean Source: https://docs.sendkit.dev/knowledge-base/digitalocean Learn how to verify your domain on SendKit using DigitalOcean DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [DigitalOcean Control Panel](https://cloud.digitalocean.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to DigitalOcean, go to **Networking > Domains**, select your domain. Click **Add Record** for each of the following. ### 1. DKIM record Click the **TXT** tab at the top of the records section. In the **Hostname** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as `3600` and click **Create Record**. | DigitalOcean field | SendKit value | | ------------------ | ---------------------------- | | Type | `TXT` | | Hostname | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | | TTL | `3600` | ### 2. SPF record Click the **TXT** tab. In the **Hostname** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Leave TTL as `3600` and click **Create Record**. | DigitalOcean field | SendKit value | | ------------------ | --------------------------- | | Type | `TXT` | | Hostname | `send` | | Value | Your SPF value from SendKit | | TTL | `3600` | ### 3. MX record Click the **MX** tab. In the **Hostname** field, enter `send`. In the **Mail Provider Hostname** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as `3600` and click **Create Record**. | DigitalOcean field | SendKit value | | ---------------------- | -------------------------- | | Type | `MX` | | Hostname | `send` | | Mail Provider Hostname | Your MX value from SendKit | | Priority | `10` | | TTL | `3600` | ### 4. DMARC record (optional) Click the **TXT** tab. In the **Hostname** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Leave TTL as `3600` and click **Create Record**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. DigitalOcean DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting You need to add your domain in **Networking > Domains** before you can manage DNS records. Also make sure your domain's nameservers point to DigitalOcean (`ns1.digitalocean.com`, `ns2.digitalocean.com`, `ns3.digitalocean.com`). DigitalOcean automatically adds a trailing dot to MX hostnames. This is normal and won't affect verification. # Domain Warmup Source: https://docs.sendkit.dev/knowledge-base/domain-warmup Understand how SendKit automatically warms up new domains to protect your sending reputation. ## What is domain warmup? When you verify a new domain on SendKit, it doesn't have an established sending reputation with email providers like Gmail, Outlook, or Yahoo. Sending a large volume of emails immediately from a new domain can trigger spam filters and damage your deliverability. Domain warmup is SendKit's built-in mechanism that **automatically and gradually increases your daily sending limit** over a 7-day period. This gives email providers time to recognize your domain as a legitimate sender. You don't need to configure anything. Warmup is fully automatic and starts when you send your first email from a verified domain. ## How it works 1. **You verify your domain** — DNS records are configured and validated. 2. **You send your first email** — This starts the 7-day warmup clock. 3. **Daily limits increase automatically** — Each day, SendKit allows more emails from your domain. 4. **Warmup completes on day 8** — Your domain has no sending limits after the warmup period. The warmup clock starts on your **first email sent**, not when you verify the domain. This means you can verify your domain ahead of time without affecting the warmup schedule. ## Warmup schedules SendKit uses different warmup schedules based on your domain's age. Newer domains get a more conservative schedule to protect their reputation. ### Young domains (less than 30 days old) | Day | Daily limit | | --- | ------------ | | 1 | 50 emails | | 2 | 100 emails | | 3 | 250 emails | | 4 | 500 emails | | 5 | 1,000 emails | | 6 | 1,500 emails | | 7 | 2,000 emails | | 8+ | No limit | ### Established domains (30+ days old) | Day | Daily limit | | --- | ------------ | | 1 | 200 emails | | 2 | 500 emails | | 3 | 1,000 emails | | 4 | 2,000 emails | | 5 | 3,500 emails | | 6 | 5,000 emails | | 7 | 7,500 emails | | 8+ | No limit | Daily limits reset at midnight (UTC). SendKit automatically detects your domain's age when you add it. If we can't determine the age, your domain is treated as young (the more conservative schedule). ## What happens when you hit the limit? If you try to send more emails than your current daily limit allows, the API returns a **429 Too Many Requests** response with details about your warmup status: ```json theme={null} { "name": "warmup_limit", "message": "Domain warmup limit reached for example.com. Daily limit: 200 emails. Sent today: 200. Warmup completes on 2026-03-14.", "domain": "example.com", "daily_limit": 200, "emails_sent_today": 200, "warmup_day": 3, "warmup_ends_at": "2026-03-14T00:00:00Z" } ``` Use `warmup_ends_at` to know when your domain will be fully warmed up, and `daily_limit` to plan your sending volume accordingly. ## Free plan daily limit In addition to the warmup schedule, **Free plan accounts are limited to 100 emails per day**, even after warmup completes. This limit resets at midnight (UTC). Upgrading to a paid plan removes the daily limit. ## Warmup and campaigns When sending a campaign, SendKit respects the warmup limit of each domain and the daily limit of your plan. If either limit is reached mid-campaign, the remaining contacts won't receive the email until the next day's limit resets. Plan your campaign volume around your current warmup day and daily limit to avoid interruptions. ## Tips for a successful warmup During the first few days, send to recipients who are most likely to open and interact with your emails. Positive engagement signals help build your domain's reputation faster. Don't use purchased or scraped email lists during warmup. High bounce rates and spam complaints during this period can permanently harm your domain's reputation. Keep an eye on your bounce rate and complaint rate in the SendKit dashboard. If either spikes, pause sending and investigate before continuing. Try to send emails every day during the warmup period. Consistent sending patterns signal to email providers that you're a legitimate sender. ## FAQ No. The warmup schedule is enforced automatically to protect your sending reputation. Skipping it would risk your emails being flagged as spam. Yes. Each verified domain has an independent warmup period. Adding a new domain starts a fresh 7-day warmup for that domain only. The warmup is based on calendar days since your first email, not sending days. If you skip a day, the schedule continues — your limits still increase as planned. Yes. Batch sends count against your daily warmup limit. If a batch would exceed the limit, the entire batch is rejected. SendKit automatically detects your domain's registration date. Domains registered less than 30 days ago use the young schedule, which has lower daily limits to protect your reputation during the critical early period. # Domains Source: https://docs.sendkit.dev/knowledge-base/domains Connect your domain to SendKit to start sending emails with full authentication. ## What are domains? A domain is the foundation of your sending identity in SendKit. Before you can send any email, you need to add and verify at least one domain. This proves you own the domain and authorizes SendKit to send on your behalf. For example, if you want to send emails from `hello@acme.com`, you need to add and verify `acme.com`. ## Adding a domain Navigate to **Domains** in the sidebar and click **Add Domain**. Type your domain (e.g., `acme.com`). Do not include subdomains or protocols. Choose the region closest to your recipients for best performance. This cannot be changed after creation. SendKit generates 4 DNS records you need to add at your DNS provider. See [DNS records](#dns-records) below. After adding the records, click **Refresh** on the domain detail page. Verification usually completes within minutes, but DNS propagation can take up to a few hours. ## DNS records When you add a domain, SendKit generates 4 DNS records. You need to add these at your DNS provider (Cloudflare, AWS Route 53, GoDaddy, etc.). ### DKIM (required) DKIM cryptographically signs your emails so recipients can verify they haven't been tampered with. | Field | Value | | --------- | ------------------------------------- | | **Type** | TXT | | **Name** | `sendkit._domainkey.yourdomain.com` | | **Value** | `v=DKIM1; k=rsa; p=` | | **TTL** | 3600 | The DKIM public key is unique to your domain and generated automatically by SendKit. Copy the full value from the domain detail page. ### SPF (required) SPF tells receiving mail servers that SendKit is authorized to send emails for your domain. | Field | Value | | --------- | -------------------------------- | | **Type** | TXT | | **Name** | `send.yourdomain.com` | | **Value** | Shown on your domain detail page | | **TTL** | 3600 | ### MX (required) The MX record on the `send` subdomain enables bounce and complaint handling. | Field | Value | | ------------ | -------------------------------- | | **Type** | MX | | **Name** | `send.yourdomain.com` | | **Value** | Shown on your domain detail page | | **Priority** | 10 | | **TTL** | 3600 | The exact MX value depends on the region you selected. Copy it from your domain detail page. ### DMARC (optional) DMARC builds on top of DKIM and SPF to define how receiving servers should handle unauthenticated emails. | Field | Value | | --------- | ----------------------- | | **Type** | TXT | | **Name** | `_dmarc.yourdomain.com` | | **Value** | `v=DMARC1; p=none;` | | **TTL** | 3600 | DMARC is not required for verification, but we strongly recommend adding it. It protects your domain from spoofing and improves deliverability. ## Verification After you add the DNS records at your provider, come back to the domain detail page and click **Refresh**. SendKit checks both your DNS records and the email identity status. ### Statuses | Status | Meaning | | ---------------------- | ----------------------------------------------------------------------------- | | **Not started** | Domain was just added, no verification attempted yet | | **Pending** | Verification in progress — DNS records detected but still propagating | | **Verified** | All required records confirmed. You can send emails | | **Partially verified** | Some records verified, but not all required ones | | **Failed** | Required records not found or incorrect | | **Temporary failure** | A transient issue occurred during verification. Will be retried automatically | If a verified domain loses its DNS records (e.g., someone removes them), SendKit detects this automatically and disables sending. You'll receive an email notification and need to re-add the records. ### Automatic checks You don't need to keep clicking Refresh. SendKit automatically checks pending domains: * **First 2 hours** — every 10 minutes * **2–12 hours** — every 30 minutes * **12–72 hours** — every 60 minutes After 72 hours, automatic checks stop. You can still verify manually at any time. ## Domain configuration Once added, you can configure tracking and security settings from the **Configuration** tab: ### Click tracking When enabled, links in your HTML emails are rewritten to pass through SendKit before redirecting to the original URL. This lets you track which recipients clicked which links. ### Open tracking Not recommended. Many email clients block tracking pixels, making open data unreliable. It can also affect deliverability. When enabled, a 1x1 transparent pixel is inserted into each email to detect when it's opened. ### TLS mode | Mode | Behavior | | --------------------------- | ----------------------------------------------------------------------------------------------- | | **Opportunistic** (default) | Attempts TLS encryption, falls back to unencrypted if the recipient's server doesn't support it | | **Enforced** | Requires TLS. If the recipient's server doesn't support TLS, the email is rejected | ## Domains and senders Domains and [senders](/knowledge-base/senders) work together: * A domain must be **verified** before you can create senders on it * Each sender uses an email address on a verified domain (e.g., `hello@acme.com`) * If a domain loses verification, all senders on that domain are disabled until re-verified ## Domain warmup New domains go through an automatic [warmup period](/knowledge-base/domain-warmup) to build sender reputation. During warmup, daily sending volume is gradually increased over 7 days. The schedule varies based on your domain's age — younger domains get a more conservative warmup. ## Deleting a domain A domain can only be deleted if it has **no senders**. Remove all senders first, then delete the domain from the dropdown menu on the domain detail page. When a domain is deleted: * The domain and its DNS records are removed from SendKit * All associated infrastructure is cleaned up automatically * You can remove the DNS records from your provider Deleting a domain does not affect emails that were already sent. ## FAQ The number of domains depends on your plan. Check your plan details for the domain limit. Yes. You can add `mail.acme.com` or any subdomain. The DNS records will be generated for that subdomain. Most DNS providers propagate changes within minutes. In rare cases, it can take up to 24-48 hours depending on your provider and TTL settings. DKIM, SPF, and MX are required for verification. DMARC is optional but strongly recommended for better deliverability and domain protection. Choose the region closest to the majority of your recipients. This reduces latency and can improve delivery speed. The region cannot be changed after domain creation. No. Each domain is unique per team. However, different teams can use different subdomains of the same root domain. # DreamHost Source: https://docs.sendkit.dev/knowledge-base/dreamhost Learn how to verify your domain on SendKit using DreamHost DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [DreamHost panel](https://panel.dreamhost.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to the DreamHost panel and go to **Domains > DNS**. Select your domain, then click **Add Record** for each of the following. ### 1. DKIM record Click **Add Record** and select **TXT** as the type. In the **Name** field, enter `sendkit._domainkey.yourdomain.com` (DreamHost requires the full hostname). In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Click **Add Record**. DreamHost requires the full hostname including your domain. Enter `sendkit._domainkey.yourdomain.com`, not just `sendkit._domainkey`. | DreamHost field | SendKit value | | --------------- | ----------------------------------- | | Type | `TXT` | | Name | `sendkit._domainkey.yourdomain.com` | | Value | Your DKIM value from SendKit | ### 2. SPF record Click **Add Record** and select **TXT** as the type. In the **Name** field, enter `send.yourdomain.com`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Click **Add Record**. | DreamHost field | SendKit value | | --------------- | --------------------------- | | Type | `TXT` | | Name | `send.yourdomain.com` | | Value | Your SPF value from SendKit | ### 3. MX record Click **Add Record** and select **MX** as the type. In the **Name** field, enter `send.yourdomain.com`. In the **Value** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Add Record**. | DreamHost field | SendKit value | | --------------- | -------------------------- | | Type | `MX` | | Name | `send.yourdomain.com` | | Value | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Click **Add Record** and select **TXT** as the type. In the **Name** field, enter `_dmarc.yourdomain.com`. In the **Value** field, enter `v=DMARC1; p=none;`. Click **Add Record**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. DreamHost DNS changes can take up to 30 minutes to propagate. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting DreamHost requires the full hostname including your domain. Unlike most providers, it does not automatically append the domain to the name field. If your nameservers point elsewhere, DreamHost won't serve your DNS records. Make sure your domain is using DreamHost nameservers or manage DNS at your active provider. # Dynadot Source: https://docs.sendkit.dev/knowledge-base/dynadot Learn how to verify your domain on SendKit using Dynadot DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Dynadot account](https://www.dynadot.com/account) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Dynadot, go to **My Domains > Manage Domains**, click your domain, then select **DNS Settings**. Make sure DNS is set to **Dynadot DNS** and add each of the following records. ### 1. DKIM record In the DNS Records section, click **Add DNS Record** and select **TXT**. In the **Subdomain** field, enter `sendkit._domainkey`. In the **Text** field, paste the full DKIM value from your SendKit domain detail page. Click **Save DNS**. | Dynadot field | SendKit value | | ------------- | ---------------------------- | | Type | `TXT` | | Subdomain | `sendkit._domainkey` | | Text | Your DKIM value from SendKit | ### 2. SPF record Click **Add DNS Record** and select **TXT**. In the **Subdomain** field, enter `send`. In the **Text** field, paste the SPF value from your SendKit domain detail page. Click **Save DNS**. | Dynadot field | SendKit value | | ------------- | --------------------------- | | Type | `TXT` | | Subdomain | `send` | | Text | Your SPF value from SendKit | ### 3. MX record Click **Add DNS Record** and select **MX**. In the **Subdomain** field, enter `send`. In the **Mail Host** field, paste the MX value from your SendKit domain detail page. Set **Distance** (priority) to `10`. Click **Save DNS**. Dynadot uses "Distance" instead of "Priority" for MX records. They mean the same thing — set it to `10`. | Dynadot field | SendKit value | | ------------- | -------------------------- | | Type | `MX` | | Subdomain | `send` | | Mail Host | Your MX value from SendKit | | Distance | `10` | ### 4. DMARC record (optional) Click **Add DNS Record** and select **TXT**. In the **Subdomain** field, enter `_dmarc`. In the **Text** field, enter `v=DMARC1; p=none;`. Click **Save DNS**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Dynadot DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Make sure the DNS type is set to **Dynadot DNS** (not custom nameservers). If you're using external nameservers, manage DNS at that provider instead. Dynadot requires you to click **Save DNS** after adding each record. Changes won't take effect until saved. # Email Activity Source: https://docs.sendkit.dev/knowledge-base/email-activity Track every email you send with real-time status updates, filtering, and a detailed event timeline. ## What is email activity? The Email Activity page is a real-time log of every email sent through SendKit — via API, campaigns, or automations. You can search, filter, and inspect individual emails to see exactly what happened from send to delivery. ## Email list The main view shows a paginated list of all emails with: | Column | Description | | ----------- | ------------------------------------------------------ | | **To** | Recipient email address | | **Subject** | Email subject line | | **Status** | Current status badge (see [statuses](#statuses) below) | | **Domain** | The sending domain used | | **Date** | When the email was created | The list updates in real time — new events appear automatically without refreshing the page. ## Statuses Each email tracks its **last event**, which represents the most recent (and most advanced) state in its lifecycle. | Status | Meaning | | -------------------- | --------------------------------------------------------------------------------------------------------- | | **Sent** | Email was accepted and dispatched for delivery | | **Delivered** | Email was successfully delivered to the recipient's mail server | | **Opened** | Recipient opened the email (requires [open tracking](/knowledge-base/domains#open-tracking)) | | **Clicked** | Recipient clicked a link in the email (requires [click tracking](/knowledge-base/domains#click-tracking)) | | **Bounced** | Recipient's mail server rejected the email | | **Complained** | Recipient marked the email as spam | | **Failed** | Email was permanently rejected before delivery | | **Delivery delayed** | Delivery is temporarily delayed and will be retried | | **Suppressed** | Email was blocked because the address is on the [suppression list](/knowledge-base/suppression-list) | | **Rejected** | Email was rejected before sending (e.g., validation failure, policy block) | | **Cancelled** | Email was cancelled before being sent | ### Status progression Statuses follow a priority order. An email only moves forward — it won't go back to a previous state: ``` Sent → Delivered → Opened → Clicked ``` Negative outcomes (bounced, complained, failed) are terminal — they replace the current status. ## Searching and filtering ### Search Search by recipient email address using the search bar. Results update as you type. ### Date range Select a custom date range using the date picker. The available range depends on your plan's data retention policy. ### Advanced filters Click the filter button to open advanced filters: | Filter | Description | | -------------- | ------------------------------------------------------------------------------------------------------- | | **Status** | Select one or more statuses (sent, delivered, opened, clicked, bounced, complained, failed, suppressed) | | **Domain** | Filter by sending domain | | **Campaign** | Filter emails sent from a specific campaign | | **Automation** | Filter emails sent from a specific automation | All filters work together (AND logic). Active filters appear as removable badges below the toolbar. ## Email detail Click any email to see its full detail page. ### Metadata The header shows key information about the email: * **From** — Sender email address * **To** — Recipient email address * **Template** — Link to the template used (if applicable) * **ID** — Unique email identifier (with copy button) * **CC / BCC / Reply-To** — If set ### Tags If the email was sent with tags (via the [API](/api-reference/endpoint/send-email)), they appear as badges. Tags help you categorize and identify emails — for example, `transactional`, `welcome`, or `invoice`. ### Event timeline A chronological timeline shows every event that occurred for this email, from send to delivery (or failure). Each event includes: * **Event type** — With a color-coded icon * **Timestamp** — When the event occurred | Event | Icon color | Description | | -------------- | ---------- | ---------------------------------------- | | **Sent** | Blue | Email dispatched to mail server | | **Delivered** | Green | Confirmed delivery to recipient's server | | **Opened** | Purple | Recipient opened the email | | **Clicked** | Cyan | Recipient clicked a link | | **Bounced** | Orange | Email rejected by recipient's server | | **Complained** | Red | Marked as spam by recipient | | **Failed** | Red | Permanently rejected | ### Email content Three tabs let you inspect the email body: * **Preview** — Rendered HTML as the recipient sees it * **HTML** — Raw HTML source code with copy button * **Plain Text** — Plain text version of the email ## Data retention Email activity data is retained based on your plan. Older emails are automatically removed after the retention period. The available date range in filters reflects your plan's retention window. ## Real-time updates Both the email list and detail pages update in real time via WebSocket. When a new event occurs (delivery confirmation, open, click, bounce), you see it immediately — no need to refresh. ## FAQ Not directly from the activity page. You can send the email again via the API or by creating a new campaign targeting the same contact. Open tracking depends on a tracking pixel being loaded. Many email clients block images by default, so opens are often underreported. The email was delivered — the recipient may have read it without triggering the open event. **Failed** means the email was rejected before delivery (e.g., invalid configuration, domain not verified). **Bounced** means the email reached the recipient's server but was rejected (e.g., address doesn't exist, mailbox full). Click events are tracked in the event timeline. The specific URL clicked is recorded as part of the event data. The available history depends on your plan's data retention policy. Check your plan details for the exact retention period. # Email Validation Source: https://docs.sendkit.dev/knowledge-base/email-validation Verify email addresses before sending to reduce bounces, protect your reputation, and save money. ## Why validate emails? Sending to invalid, disposable, or non-existent email addresses wastes resources and damages your sender reputation. Every bounce counts against you with email providers like Gmail and Outlook. SendKit's email validation lets you **verify addresses before you send** — catching bad emails before they become bounces. ## What gets checked Each validation runs multiple checks and returns a confidence level (`HIGH` or `LOW`) for each: | Check | What it detects | | ---------------- | ---------------------------------------------------------------------------------------- | | **Syntax** | Whether the email format is valid (e.g., missing `@`, invalid characters) | | **DNS** | Whether the domain has valid MX records that can receive email | | **Mailbox** | Whether the specific mailbox exists on the mail server | | **Role address** | Whether it's a group address like `info@`, `admin@`, or `support@` | | **Disposable** | Whether it's from a disposable/temporary email service like Mailinator or Guerrilla Mail | | **Random input** | Whether the local part of the email appears to be randomly generated characters | ## Reading the results Every validation returns a clear verdict: * **`is_valid`** — Overall validity (`HIGH` = safe to send, `LOW` = risky) * **`should_block`** — Boolean recommendation on whether to block the address * **`block_reason`** — If blocked, the specific reason why: | Block reason | Meaning | | ------------------ | ------------------------------------- | | `invalid_syntax` | The email format is malformed | | `invalid` | The email is invalid or undeliverable | | `disposable_email` | It's a throwaway address | ## Using validation ### From the dashboard Go to **Email Validation** in the sidebar, enter an email address, and get instant results. Your validation history is saved so you can review past checks. ### From the API Validate an email programmatically via the [API](/api-reference/endpoint/validate-email). The response includes all evaluation fields so you can make your own decisions about what to block. ### Automatic validation on send SendKit also validates recipients automatically when you send an email. If a recipient has invalid syntax or uses a disposable domain, the email is **blocked before it's sent** — protecting your reputation without any extra code. Automatic validation on send uses local checks only (syntax, disposable). It doesn't consume credits. Credit-based validation via the API or dashboard includes deeper checks like DNS, mailbox verification, and more. ## Credits Each email validation costs **1 credit**. You can purchase credit packages from the dashboard under **Settings > Billing**. * Credits are shared across your team * Validations from both the dashboard and API consume credits * If you run out of credits, the API returns a `402` error ### Auto-reload You can configure auto-reload to automatically purchase more credits when your balance drops below a threshold. Set this up in **Settings > Billing** to avoid interruptions. ## Smart caching SendKit caches validation results to save credits and speed up repeated lookups: | Result | Cache duration | | ------------- | -------------- | | Valid email | 90 days | | Invalid email | 180 days | | Disposable | Forever | If you validate the same email within the cache window, the cached result is returned instantly at no extra cost. ## FAQ No. Automatic validation during email sending uses local checks and is free. Only explicit validation requests (via API or dashboard) consume credits. Local validation checks syntax and disposable status using SendKit's own systems. Full validation (API/dashboard) additionally checks DNS records, verifies whether the mailbox actually exists on the mail server, and detects role addresses. For transactional emails to known users (e.g., password resets), it's usually not necessary — SendKit's automatic checks handle bad addresses. For marketing campaigns or new signups, validating upfront helps reduce bounce rates significantly. Currently, the API validates one email per request. You can send multiple requests in parallel for bulk validation. # Gandi Source: https://docs.sendkit.dev/knowledge-base/gandi Learn how to verify your domain on SendKit using Gandi DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Gandi account](https://admin.gandi.net) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Gandi, go to **Domain**, select your domain, then click the **DNS Records** tab. Click **Add Record** for each of the following. ### 1. DKIM record Click **Add Record** and select **TXT** as the type. In the **Name** field, enter `sendkit._domainkey`. In the **Text Value** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as the default (`10800`) and click **Create**. | Gandi field | SendKit value | | ----------- | ---------------------------- | | Type | `TXT` | | Name | `sendkit._domainkey` | | Text Value | Your DKIM value from SendKit | | TTL | `10800` | ### 2. SPF record Click **Add Record** and select **TXT** as the type. In the **Name** field, enter `send`. In the **Text Value** field, paste the SPF value from your SendKit domain detail page. Leave TTL as the default and click **Create**. | Gandi field | SendKit value | | ----------- | --------------------------- | | Type | `TXT` | | Name | `send` | | Text Value | Your SPF value from SendKit | | TTL | `10800` | ### 3. MX record Click **Add Record** and select **MX** as the type. In the **Name** field, enter `send`. In the **Hostname** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as the default and click **Create**. | Gandi field | SendKit value | | ----------- | -------------------------- | | Type | `MX` | | Name | `send` | | Hostname | Your MX value from SendKit | | Priority | `10` | | TTL | `10800` | ### 4. DMARC record (optional) Click **Add Record** and select **TXT** as the type. In the **Name** field, enter `_dmarc`. In the **Text Value** field, enter `v=DMARC1; p=none;`. Leave TTL as the default and click **Create**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Gandi DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting These instructions assume you're using Gandi's LiveDNS. If your domain uses external nameservers, manage DNS at that provider instead. Some Gandi configurations require a trailing dot on MX hostnames (e.g., `mail.example.com.`). If verification fails, try adding a dot at the end of the MX value. # GoDaddy Source: https://docs.sendkit.dev/knowledge-base/godaddy Learn how to verify your domain on SendKit using GoDaddy DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [GoDaddy account](https://dcc.godaddy.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to GoDaddy, go to **My Products > Domains**, click your domain, then go to **DNS > DNS Records**. Click **Add New Record** for each of the following. ### 1. DKIM record Click **Add New Record** and select **TXT** as the type. In the **Name** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as the default and click **Save**. | GoDaddy field | SendKit value | | ------------- | ---------------------------- | | Type | `TXT` | | Name | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | | TTL | Default | ### 2. SPF record Click **Add New Record** and select **TXT** as the type. In the **Name** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Leave TTL as the default and click **Save**. | GoDaddy field | SendKit value | | ------------- | --------------------------- | | Type | `TXT` | | Name | `send` | | Value | Your SPF value from SendKit | | TTL | Default | ### 3. MX record Click **Add New Record** and select **MX** as the type. In the **Name** field, enter `send`. In the **Value** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as the default and click **Save**. | GoDaddy field | SendKit value | | ------------- | -------------------------- | | Type | `MX` | | Name | `send` | | Value | Your MX value from SendKit | | Priority | `10` | | TTL | Default | ### 4. DMARC record (optional) Click **Add New Record** and select **TXT** as the type. In the **Name** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Leave TTL as the default and click **Save**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. GoDaddy DNS changes can take up to 30 minutes to propagate. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting GoDaddy may truncate long TXT values in the display, but the full value is stored. Copy the value directly from SendKit and paste it — the record will work correctly. If your domain uses external nameservers, GoDaddy won't manage DNS for it. Check your nameserver settings under **DNS > Nameservers**. You should only have one MX record on `send.yourdomain.com`. If there's a conflicting record, remove it before adding the SendKit MX record. # Google Cloud DNS Source: https://docs.sendkit.dev/knowledge-base/google-cloud-dns Learn how to verify your domain on SendKit using Google Cloud DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Google Cloud Console](https://console.cloud.google.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Google Cloud Console, go to **Network services > Cloud DNS**, select your managed zone. Click **Add standard** for each of the following. ### 1. DKIM record Click **Add standard**. In the **DNS name** field, enter `sendkit._domainkey`. Choose **TXT** from the Resource record type dropdown. In the **Routing data** field, paste the DKIM value from SendKit **wrapped in double quotes**. Leave TTL as `3600` and click **Create**. Google Cloud DNS requires TXT record values to be enclosed in **double quotes**. If you paste the value without quotes, the record will fail. | Cloud DNS field | SendKit value | | -------------------- | ---------------------------------------------- | | DNS name | `sendkit._domainkey` | | Resource record type | `TXT` | | Routing data | `"your DKIM value from SendKit"` (with quotes) | | TTL | `3600` | ### 2. SPF record Click **Add standard**. Enter `send`. Choose **TXT**. Paste the SPF value from SendKit **wrapped in double quotes**. Leave TTL as `3600` and click **Create**. | Cloud DNS field | SendKit value | | -------------------- | --------------------------------------------- | | DNS name | `send` | | Resource record type | `TXT` | | Routing data | `"your SPF value from SendKit"` (with quotes) | | TTL | `3600` | ### 3. MX record Click **Add standard**. Enter `send`. Choose **MX**. Enter the priority followed by the MX value: `10 your-mx-value-from-sendkit.` Leave TTL as `3600` and click **Create**. In Cloud DNS, MX records combine the priority and value in one field. Enter `10` followed by a space, then the MX value from SendKit with a trailing dot (e.g., `10 feedback-smtp.us-east-2.amazonses.com.`). | Cloud DNS field | SendKit value | | -------------------- | -------------------------------- | | DNS name | `send` | | Resource record type | `MX` | | Routing data | `10 your-mx-value-from-sendkit.` | | TTL | `3600` | ### 4. DMARC record (optional) Click **Add standard**. Enter `_dmarc`. Choose **TXT**. Enter `"v=DMARC1; p=none;"` (with quotes). Leave TTL as `3600` and click **Create**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Google Cloud DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Google Cloud DNS requires all TXT values to be wrapped in double quotes. If verification fails, check that your records include the quotes. Cloud DNS uses fully qualified domain names. Add a trailing dot (`.`) at the end of the MX value. Make sure you've created a managed zone for your domain and that your domain's nameservers point to the ones listed in the zone details (e.g., `ns-cloud-a1.googledomains.com`). # Hetzner Source: https://docs.sendkit.dev/knowledge-base/hetzner Learn how to verify your domain on SendKit using Hetzner DNS Console. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Hetzner DNS Console](https://dns.hetzner.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to the Hetzner DNS Console, select your DNS zone, then click **Add record** for each of the following. ### 1. DKIM record Click **Add record** and select **TXT** as the type. In the **Name** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Click **Add record**. | Hetzner field | SendKit value | | ------------- | ---------------------------- | | Type | `TXT` | | Name | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | ### 2. SPF record Click **Add record** and select **TXT** as the type. In the **Name** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Click **Add record**. | Hetzner field | SendKit value | | ------------- | --------------------------- | | Type | `TXT` | | Name | `send` | | Value | Your SPF value from SendKit | ### 3. MX record Click **Add record** and select **MX** as the type. In the **Name** field, enter `send`. In the **Value** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Add record**. | Hetzner field | SendKit value | | ------------- | -------------------------- | | Type | `MX` | | Name | `send` | | Value | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Click **Add record** and select **TXT** as the type. In the **Name** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Click **Add record**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Hetzner DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Make sure you've added your domain as a DNS zone in the Hetzner DNS Console and that your domain's nameservers point to Hetzner (`hydrogen.ns.hetzner.com`, `oxygen.ns.hetzner.com`, `helium.ns.hetzner.de`). Hetzner DNS Console handles long TXT values correctly. Paste the full DKIM value from SendKit without splitting it into chunks. # Hostinger Source: https://docs.sendkit.dev/knowledge-base/hostinger Learn how to verify your domain on SendKit using Hostinger DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Hostinger hPanel](https://hpanel.hostinger.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to hPanel, go to **Domains**, click your domain, then navigate to **DNS / Nameservers > DNS Records**. Click **Add Record** for each of the following. ### 1. DKIM record Select **TXT** as the record type. In the **Name** field, enter `sendkit._domainkey` (Hostinger appends your domain automatically). In the **TXT Value** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as `14400` (default) and click **Add Record**. | Hostinger field | SendKit value | | --------------- | ---------------------------- | | Type | `TXT` | | Name | `sendkit._domainkey` | | TXT Value | Your DKIM value from SendKit | | TTL | `14400` | ### 2. SPF record Select **TXT** as the record type. In the **Name** field, enter `send`. In the **TXT Value** field, paste the SPF value from your SendKit domain detail page. Leave TTL as `14400` and click **Add Record**. | Hostinger field | SendKit value | | --------------- | --------------------------- | | Type | `TXT` | | Name | `send` | | TXT Value | Your SPF value from SendKit | | TTL | `14400` | ### 3. MX record Select **MX** as the record type. In the **Name** field, enter `send`. In the **Mail Server** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as `14400` and click **Add Record**. | Hostinger field | SendKit value | | --------------- | -------------------------- | | Type | `MX` | | Name | `send` | | Mail Server | Your MX value from SendKit | | Priority | `10` | | TTL | `14400` | ### 4. DMARC record (optional) Select **TXT** as the record type. In the **Name** field, enter `_dmarc`. In the **TXT Value** field, enter `v=DMARC1; p=none;`. Leave TTL as `14400` and click **Add Record**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Hostinger DNS changes can take up to 30 minutes to propagate. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Hostinger uses a default TTL of 14400 seconds (4 hours) for DNS records. While new records usually appear faster, full propagation can take up to 4 hours in some cases. Make sure your domain is using Hostinger nameservers. If you've pointed your nameservers elsewhere, manage DNS at that provider instead. # Hover Source: https://docs.sendkit.dev/knowledge-base/hover Learn how to verify your domain on SendKit using Hover DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Hover account](https://www.hover.com/control_panel) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Hover, go to your domain, then click the **DNS** tab. Click **Add A Record** for each of the following. ### 1. DKIM record Click **Add A Record** and select **TXT** as the type. In the **Hostname** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Click **Add Record**. | Hover field | SendKit value | | ----------- | ---------------------------- | | Type | `TXT` | | Hostname | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | ### 2. SPF record Click **Add A Record** and select **TXT**. In the **Hostname** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Click **Add Record**. | Hover field | SendKit value | | ----------- | --------------------------- | | Type | `TXT` | | Hostname | `send` | | Value | Your SPF value from SendKit | ### 3. MX record Click **Add A Record** and select **MX**. In the **Hostname** field, enter `send`. In the **Value** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Add Record**. | Hover field | SendKit value | | ----------- | -------------------------- | | Type | `MX` | | Hostname | `send` | | Value | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Click **Add A Record** and select **TXT**. In the **Hostname** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Click **Add Record**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Hover DNS changes typically propagate within 15 minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting If you've changed your nameservers away from Hover, DNS records must be managed at your active DNS provider. Hover's DNS tab only works when using Hover's default nameservers. Despite the button label, you can add any record type (TXT, MX, CNAME, etc.) — not just A records. Select the correct type from the dropdown after clicking. # Introduction Source: https://docs.sendkit.dev/knowledge-base/introduction Learn the fundamentals of SendKit and how to send your first email ## What is SendKit? SendKit is an email delivery platform built for developers. It provides a simple API to send transactional and marketing emails at scale, with built-in deliverability tools, analytics, and team management. ## Key features Send emails with a single API call. Supports HTML, plain text, and attachments. Verify your sending domains with SPF, DKIM, and DMARC records to maximize deliverability. Track opens, clicks, bounces, and complaints in real time. Invite team members and manage API keys with role-based access. ## How it works Sign up at [app.sendkit.dev](https://app.sendkit.dev) and create your team. Add your sending domain and configure the DNS records to verify ownership. Create an API key from the dashboard to authenticate your requests. Use the API to send an email. Here's a quick example: ```bash theme={null} curl -X POST https://api.sendkit.dev/emails \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Hello from SendKit", "html": "

Your first email sent with SendKit!

" }' ```
## Next steps Explore the full API documentation. # IONOS Source: https://docs.sendkit.dev/knowledge-base/ionos Learn how to verify your domain on SendKit using IONOS DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [IONOS account](https://my.ionos.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to IONOS, go to **Domains & SSL**, click your domain, then select **DNS**. Click **Add Record** for each of the following. ### 1. DKIM record Click **Add Record** and select **TXT** as the record type. In the **Hostname** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Click **Save**. | IONOS field | SendKit value | | ----------- | ---------------------------- | | Type | `TXT` | | Hostname | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | ### 2. SPF record Click **Add Record** and select **TXT** as the record type. In the **Hostname** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Click **Save**. | IONOS field | SendKit value | | ----------- | --------------------------- | | Type | `TXT` | | Hostname | `send` | | Value | Your SPF value from SendKit | ### 3. MX record Click **Add Record** and select **MX** as the record type. In the **Hostname** field, enter `send`. In the **Points to** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Save**. | IONOS field | SendKit value | | ----------- | -------------------------- | | Type | `MX` | | Hostname | `send` | | Points to | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Click **Add Record** and select **TXT** as the record type. In the **Hostname** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Click **Save**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. IONOS DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Make sure you're in the **DNS** section, not the **Mail** section. IONOS has separate sections for mail configuration and raw DNS records. The SendKit MX record goes on the `send` subdomain, not your root domain. It won't conflict with IONOS email or any existing MX records on your main domain. # Lists & Segments Source: https://docs.sendkit.dev/knowledge-base/lists-and-segments Two ways to organize your contacts — static lists you manage manually, and dynamic segments that update automatically. ## Two ways to group contacts SendKit gives you two approaches to organizing contacts. Use them separately or together depending on your needs. | | Lists | Segments | | -------------------------- | ----------------------------------------- | ------------------------------------------------------- | | **Type** | Static | Dynamic | | **How contacts are added** | Manually (you add/remove them) | Automatically (based on filter conditions) | | **Updates** | Only changes when you change it | Updates in real time as contacts match or stop matching | | **Best for** | Curated groups, imports, manual targeting | Behavioral targeting, conditional audiences | ## Lists Lists are static groups of contacts. You explicitly add contacts to a list and remove them when needed. They don't change on their own. ### When to use lists * Importing a group of contacts from a CSV * Organizing contacts by source (e.g., "Webinar Attendees", "Beta Users") * Building a fixed audience for a specific campaign * Triggering automations when a contact is added ### Creating a list Go to **Contacts > Lists** and click **Create List**. Give it a name and start adding contacts. You can add contacts to a list from: * The list detail page * A contact's detail page * The [API](/api-reference/endpoint/add-contacts-to-list) ### Lists and automations When a contact is added to a list, SendKit can automatically enroll them in active automations that target that list. This is a powerful way to trigger onboarding flows, drip campaigns, or follow-up sequences. A list cannot be deleted if it's used by an active campaign or automation. Update those first. *** ## Segments Segments are dynamic groups defined by filter conditions. Contacts are automatically included when they match your conditions and excluded when they don't. You never manually add or remove contacts from a segment. ### When to use segments * Targeting contacts based on attributes (e.g., "First name is set") * Creating audiences based on custom properties (e.g., "Plan is Pro") * Building conditional groups that stay up to date automatically * Combining multiple conditions with AND/OR logic ### Creating a segment Go to **Contacts > Segments** and click **Create Segment**. Then build your filter conditions. ### Filter conditions Each condition consists of a **field**, an **operator**, and a **value**: **Available fields:** * Built-in: `email`, `first_name`, `last_name`, `unsubscribed` * Custom: any [Property](/knowledge-base/properties) you've created **Available operators:** | Operator | Works with | Example | | --------------------- | ---------- | ----------------------------------- | | Equals | All types | Email equals `user@example.com` | | Not equals | All types | First name not equals `Test` | | Contains | Text | Email contains `@gmail.com` | | Not contains | Text | Email not contains `noreply` | | Starts with | Text | Last name starts with `Mc` | | Ends with | Text | Email ends with `.edu` | | Greater than | Numbers | Credits greater than `100` | | Greater than or equal | Numbers | Credits greater than or equal `100` | | Less than | Numbers | Age less than `30` | | Less than or equal | Numbers | Age less than or equal `30` | | Is set | All types | First name is set (not empty) | | Is not set | All types | Last name is not set | ### Match logic Segments support nested groups with AND/OR logic: * **Match all** — A contact must match every condition group (AND) * **Match any** — A contact must match at least one condition group (OR) Within each group, conditions can also use AND or OR logic. This lets you build sophisticated audiences like: > (Plan is "Pro" AND Country is "US") OR (Signed up before 2026-01-01) ### Real-time resolution Segments are resolved dynamically every time they're queried. There's no sync delay — when a contact's data changes, they immediately appear in or disappear from matching segments. ## FAQ Yes. A contact can belong to as many lists as you want. Yes. Segments are independent — a contact appears in every segment whose conditions they match. Yes. When creating a campaign, you can target a list or a segment as your audience. Yes. Any [Property](/knowledge-base/properties) you create can be used as a condition in segment filters, with all the same operators. The contacts are not deleted — only the list and the associations are removed. The contacts remain in your account. # Metrics Source: https://docs.sendkit.dev/knowledge-base/metrics Understand your email performance with real-time analytics and reputation monitoring. ## Overview The Metrics dashboard gives you a real-time view of your email sending performance. It tracks every email from the moment it's sent through delivery, opens, clicks, bounces, and complaints — helping you understand what's working and catch problems early. ## Filtering You can narrow your metrics using two filters: * **Domain** — View metrics for a specific domain or all domains combined * **Date range** — Select a custom time period. The available range depends on your plan's data retention policy ## Email metrics These are the six core metrics tracked for every email you send. ### Sent The total number of emails created and dispatched through SendKit — via API, campaigns, or automations. This is the base metric used as the denominator for all rate calculations. ### Delivered Emails that were successfully accepted by the recipient's mail server. An email counts as delivered if the receiving server confirmed receipt. "Delivered" means the email reached the server, not necessarily the inbox. It could still land in spam depending on content and sender reputation. **Includes:** Emails that were later opened or clicked — since delivery always happens before engagement. ### Opened Emails where the recipient opened the message. Opens are detected via a small tracking pixel embedded in the email. Open tracking must be enabled on your [domain configuration](/knowledge-base/domains#open-tracking). Many email clients block tracking pixels, so open rates are typically underreported. Use this metric as a directional signal, not an exact count. **Includes:** Emails that were later clicked — since opening always happens before clicking. ### Clicked Emails where the recipient clicked at least one link. Clicks are tracked by routing links through SendKit before redirecting to the original URL. Click tracking must be enabled on your [domain configuration](/knowledge-base/domains#click-tracking). ### Bounced Emails that were rejected by the recipient's mail server. This typically happens when: * The email address doesn't exist * The recipient's mailbox is full * The receiving server blocked the email Bounces directly affect your [sender reputation](#reputation). A high bounce rate signals to mail providers that you're sending to invalid addresses. ### Complained Emails where the recipient marked the message as spam. This is the most damaging metric for your reputation. Keep your complaint rate below **0.1%**. Even a small number of complaints can trigger warnings or pause your sending. Always include an easy unsubscribe option and only send to contacts who expect your emails. ## Rate metrics Rates give you a percentage view of your performance, making it easier to compare across different time periods and sending volumes. ### Deliverability rate The percentage of sent emails that were successfully delivered. | | | | ------------------- | --------------------------------------------------------------------- | | **Formula** | (Delivered ÷ Sent) × 100% | | **Healthy range** | Above 95% | | **What affects it** | Invalid addresses, blocklists, authentication issues, content filters | A high deliverability rate means your emails are reaching recipients. If this drops, check for bounces and review your [suppression list](/knowledge-base/suppression-list). ### Bounce rate The percentage of sent emails that bounced. | | | | ---------------------- | -------------------------------------------------- | | **Formula** | (Bounced ÷ Sent) × 100% | | **Warning threshold** | 5% | | **Critical threshold** | 10% | | **What affects it** | Invalid addresses, stale contact lists, blocklists | Use [email validation](/knowledge-base/email-validation) before sending to clean your contact list and reduce bounces. ### Complaint rate The percentage of sent emails that were marked as spam by recipients. | | | | ---------------------- | -------------------------------------------------------------------------------------------- | | **Formula** | (Complained ÷ Sent) × 100% | | **Warning threshold** | 0.1% | | **Critical threshold** | 0.5% | | **What affects it** | Unwanted emails, missing unsubscribe link, misleading content, sending to unengaged contacts | This is the most important rate to monitor. Mail providers like Gmail and Outlook heavily penalize senders with high complaint rates. ## Reputation The reputation badge in the top-right corner gives you an at-a-glance view of your sending health based on the **last 24 hours**: | Status | Meaning | | ----------- | ------------------------------------------------------------------------------------------------------- | | **Healthy** | Bounce rate below 5% and complaint rate below 0.1%. Everything is normal | | **Warned** | Bounce rate between 5–10% or complaint rate between 0.1–0.5%. Take action to improve | | **Paused** | Bounce rate 10% or above, or complaint rate 0.5% or above. Sending is paused to protect your reputation | Reputation is only evaluated when you've sent at least 200 emails in the last 24 hours. Below that volume, the status remains **Healthy**. ### What to do if your reputation degrades * Review recent bounces and remove invalid addresses * Check if you're sending to contacts who haven't opted in * Make sure your unsubscribe link is visible and working * Consider slowing down your sending volume * Sending is temporarily paused to protect your domain * Clean your contact list immediately — remove bounced and unengaged contacts * Review your [suppression list](/knowledge-base/suppression-list) for patterns * Once you've addressed the issues, your reputation will recover as your 24-hour metrics improve ## Charts ### Email activity chart The main area chart shows daily trends for all six metrics overlaid on the same timeline. Use it to: * Spot sudden drops in deliverability * Identify spikes in bounces or complaints after a campaign * See engagement trends (opens and clicks) over time ### Bounce and complaint charts Two dedicated charts below the main chart give you a focused view of bounces and complaints separately. These are the metrics that matter most for reputation, so they get their own visualization. ## Trend indicators Each metric card shows a percentage change comparing the **first half** of your selected period to the **second half**. For example, if you're viewing 14 days, it compares the first 7 days to the last 7. * **Green arrow up** — Metric increased (good for sent, delivered, opened, clicked) * **Red arrow up** — Metric increased (bad for bounced, complained) * **Green arrow down** — Metric decreased (good for bounced, complained) * **Red arrow down** — Metric decreased (bad for sent, delivered, opened, clicked) ## How metrics are tracked SendKit tracks the **final state** of each email. Every email goes through a progression: ``` Sent → Delivered → Opened → Clicked ``` If an email is opened and then clicked, it counts as **clicked** (the most advanced state). This means: * **Delivered** includes emails that were opened or clicked * **Opened** includes emails that were clicked * **Clicked** is the most specific engagement metric Negative outcomes (bounced, complained, failed) are also final states — an email can only end in one state. ## FAQ Many email clients (Apple Mail, Gmail) block tracking pixels by default or pre-fetch images in ways that don't count as opens. Open rates are always underreported. Focus on click rates for a more reliable engagement signal. A bounce means the recipient's mail server rejected the email (e.g., address doesn't exist). A failure means the email couldn't be sent at all (e.g., invalid configuration, domain not verified). Metrics update in real time. As new email events come in, the dashboard refreshes automatically — no need to reload the page. Metrics are cumulative, not exclusive. A delivered email can also be opened, and an opened email can also be clicked. Each metric includes the more advanced states. The available date range depends on your plan's data retention policy. Check your plan details for the exact retention period. # Name.com Source: https://docs.sendkit.dev/knowledge-base/name-com Learn how to verify your domain on SendKit using Name.com DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Name.com account](https://www.name.com/account) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Name.com, go to **My Domains**, click your domain, then select **DNS Records**. Click **Add Record** for each of the following. ### 1. DKIM record Select **TXT** from the type dropdown. In the **Host** field, enter `sendkit._domainkey`. In the **Answer** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as `300` (default) and click **Add Record**. | Name.com field | SendKit value | | -------------- | ---------------------------- | | Type | `TXT` | | Host | `sendkit._domainkey` | | Answer | Your DKIM value from SendKit | | TTL | `300` | ### 2. SPF record Select **TXT** from the type dropdown. In the **Host** field, enter `send`. In the **Answer** field, paste the SPF value from your SendKit domain detail page. Leave TTL as `300` and click **Add Record**. | Name.com field | SendKit value | | -------------- | --------------------------- | | Type | `TXT` | | Host | `send` | | Answer | Your SPF value from SendKit | | TTL | `300` | ### 3. MX record Select **MX** from the type dropdown. In the **Host** field, enter `send`. In the **Answer** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as `300` and click **Add Record**. | Name.com field | SendKit value | | -------------- | -------------------------- | | Type | `MX` | | Host | `send` | | Answer | Your MX value from SendKit | | Priority | `10` | | TTL | `300` | ### 4. DMARC record (optional) Select **TXT** from the type dropdown. In the **Host** field, enter `_dmarc`. In the **Answer** field, enter `v=DMARC1; p=none;`. Leave TTL as `300` and click **Add Record**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Name.com uses a low default TTL (300 seconds), so DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Name.com automatically appends your domain to the host field. Enter only the subdomain part — e.g., `send` not `send.yourdomain.com`. If your domain uses nameservers other than Name.com's defaults, manage DNS at your active DNS provider instead. # Namecheap Source: https://docs.sendkit.dev/knowledge-base/namecheap Learn how to verify your domain on SendKit using Namecheap DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Namecheap account](https://www.namecheap.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Namecheap, go to **Domain List**, click **Manage** next to your domain, then go to the **Advanced DNS** tab. Click **Add New Record** for each of the following. ### 1. DKIM record Click **Add New Record** and select **TXT Record**. In the **Host** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as **Automatic** and click the green checkmark to save. | Namecheap field | SendKit value | | --------------- | ---------------------------- | | Type | `TXT Record` | | Host | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | | TTL | Automatic | ### 2. SPF record Click **Add New Record** and select **TXT Record**. In the **Host** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Leave TTL as **Automatic** and click the green checkmark to save. | Namecheap field | SendKit value | | --------------- | --------------------------- | | Type | `TXT Record` | | Host | `send` | | Value | Your SPF value from SendKit | | TTL | Automatic | ### 3. MX record Click **Add New Record** and select **MX Record**. In the **Host** field, enter `send`. In the **Value** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as **Automatic** and click the green checkmark to save. | Namecheap field | SendKit value | | --------------- | -------------------------- | | Type | `MX Record` | | Host | `send` | | Value | Your MX value from SendKit | | Priority | `10` | | TTL | Automatic | ### 4. DMARC record (optional) Click **Add New Record** and select **TXT Record**. In the **Host** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Leave TTL as **Automatic** and click the green checkmark to save. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Namecheap DNS changes typically propagate within 30 minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Make sure your domain is using **Namecheap BasicDNS** or **Namecheap PremiumDNS** as the nameserver. If you're using custom nameservers, you need to manage DNS at that provider instead. Namecheap automatically appends your domain to the host field. Enter only the subdomain part — e.g., `send` not `send.yourdomain.com`. Namecheap may truncate the display of long TXT values, but the full value is stored. Paste the complete value from SendKit and save — it will work correctly. # Netlify Source: https://docs.sendkit.dev/knowledge-base/netlify Learn how to verify your domain on SendKit using Netlify DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Netlify dashboard](https://app.netlify.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Netlify, go to **Domains**, select your domain, then scroll to the **DNS records** section. Click **Add new record** for each of the following. ### 1. DKIM record Click **Add new record** and select **TXT** as the record type. In the **Name** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Click **Save**. | Netlify field | SendKit value | | ------------- | ---------------------------- | | Type | `TXT` | | Name | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | ### 2. SPF record Click **Add new record** and select **TXT**. In the **Name** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Click **Save**. | Netlify field | SendKit value | | ------------- | --------------------------- | | Type | `TXT` | | Name | `send` | | Value | Your SPF value from SendKit | ### 3. MX record Click **Add new record** and select **MX**. In the **Name** field, enter `send`. In the **Value** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Save**. | Netlify field | SendKit value | | ------------- | -------------------------- | | Type | `MX` | | Name | `send` | | Value | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Click **Add new record** and select **TXT**. In the **Name** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Click **Save**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Netlify DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Netlify DNS only works if your domain's nameservers point to Netlify. Check **Domains > your domain > Name servers** to verify. If you use Netlify for hosting but another provider for DNS, add the records there instead. Make sure you have Owner or Admin access to the Netlify team that manages the domain. Collaborators may not have permission to modify DNS records. # OVHcloud Source: https://docs.sendkit.dev/knowledge-base/ovhcloud Learn how to verify your domain on SendKit using OVHcloud DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [OVHcloud Control Panel](https://www.ovh.com/manager) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to OVHcloud, go to **Domain names**, select your domain, then click the **DNS zone** tab. Click **Add an entry** for each of the following. ### 1. DKIM record Click **Add an entry** and select **TXT**. In the **Subdomain** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as the default and click **Next**, then **Confirm**. | OVHcloud field | SendKit value | | -------------- | ---------------------------- | | Type | `TXT` | | Subdomain | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | ### 2. SPF record Click **Add an entry** and select **TXT**. In the **Subdomain** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Click **Next**, then **Confirm**. OVHcloud also has a dedicated SPF record type in the wizard. Use the **TXT** type instead — it works the same way and is more straightforward. | OVHcloud field | SendKit value | | -------------- | --------------------------- | | Type | `TXT` | | Subdomain | `send` | | Value | Your SPF value from SendKit | ### 3. MX record Click **Add an entry** and select **MX**. In the **Subdomain** field, enter `send`. In the **Target** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Next**, then **Confirm**. | OVHcloud field | SendKit value | | -------------- | -------------------------- | | Type | `MX` | | Subdomain | `send` | | Target | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Click **Add an entry** and select **TXT**. In the **Subdomain** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Click **Next**, then **Confirm**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. OVHcloud DNS changes can take up to 30 minutes to propagate. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Make sure you're editing the **DNS zone** tab, not the **DNS servers** tab. The DNS zone is where you add individual records. OVHcloud automatically appends a trailing dot to record names in the zone view. This is normal DNS notation and won't affect verification. The SendKit MX record goes on the `send` subdomain, not your root domain. It won't conflict with OVHcloud's email service or any existing MX records. # Porkbun Source: https://docs.sendkit.dev/knowledge-base/porkbun Learn how to verify your domain on SendKit using Porkbun DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Porkbun account](https://porkbun.com/account) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Porkbun, go to **Domain Management**, click **DNS** next to your domain. Click **Add Record** for each of the following. ### 1. DKIM record Select **TXT** from the **Type** dropdown. In the **Host** field, enter `sendkit._domainkey`. In the **Answer** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as the default and click **Add**. | Porkbun field | SendKit value | | ------------- | ---------------------------- | | Type | `TXT` | | Host | `sendkit._domainkey` | | Answer | Your DKIM value from SendKit | ### 2. SPF record Select **TXT** from the **Type** dropdown. In the **Host** field, enter `send`. In the **Answer** field, paste the SPF value from your SendKit domain detail page. Leave TTL as the default and click **Add**. | Porkbun field | SendKit value | | ------------- | --------------------------- | | Type | `TXT` | | Host | `send` | | Answer | Your SPF value from SendKit | ### 3. MX record Select **MX** from the **Type** dropdown. In the **Host** field, enter `send`. In the **Answer** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as the default and click **Add**. | Porkbun field | SendKit value | | ------------- | -------------------------- | | Type | `MX` | | Host | `send` | | Answer | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Select **TXT** from the **Type** dropdown. In the **Host** field, enter `_dmarc`. In the **Answer** field, enter `v=DMARC1; p=none;`. Leave TTL as the default and click **Add**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Porkbun DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Porkbun automatically appends your domain to the host field. Enter only the subdomain part — e.g., `send` not `send.yourdomain.com`. Porkbun may truncate long values in the list view, but the full value is stored. Copy the DKIM value directly from SendKit and paste it — it will work correctly. # Properties Source: https://docs.sendkit.dev/knowledge-base/properties Add custom fields to your contacts to store any data you need. ## What are properties? Properties are custom fields you define to store additional data on your contacts. Out of the box, contacts have email, first name, and last name. Properties let you add anything else — company name, plan type, signup date, credit balance, or whatever your application needs. ## Supported types | Type | Description | Example values | | ---------- | ------------- | ---------------------------------- | | **String** | Text field | `"Acme Corp"`, `"pro"`, `"Brazil"` | | **Number** | Numeric field | `42`, `99.90`, `1000` | | **Date** | Date field | `2026-01-15`, `2025-12-31` | ## Creating a property Go to **Contacts > Properties** and click **Create Property**. | Field | Required | Description | | ------------------ | -------- | ----------------------------------------------------------------------- | | **Key** | Yes | Unique identifier (letters, numbers, underscores). E.g., `company_name` | | **Type** | Yes | String, Number, or Date | | **Fallback value** | No | Default value used when the property isn't set on a contact | Property keys must start with a letter and can only contain letters, numbers, and underscores. Keys are unique per team. You can also create properties via the [API](/api-reference/endpoint/create-property). ## Setting values on contacts Each contact can have a value for each property. You can set values from: * The contact detail page in the dashboard * The [API](/api-reference/endpoint/update-contact) when creating or updating a contact If a property value is not set on a contact, the **fallback value** is used wherever that property is referenced (e.g., in email templates). ## Using properties in segments Properties can be used as filter conditions in [Segments](/knowledge-base/lists-and-segments). All operators are available — equals, contains, greater than, is set, etc. For example, you can create a segment for "all contacts where `plan` equals `pro`" or "all contacts where `credits` is greater than `100`". ## Using properties in templates Properties are available as merge tags in email templates. When the email is sent, the tag is replaced with the contact's value — or the fallback value if not set. ## Deleting a property A property cannot be deleted if it's used in a segment filter. Remove it from all segment conditions first. When a property is deleted, all stored values for that property across all contacts are also removed. ## FAQ There's no limit. Create as many properties as you need. It's the default value used when a contact doesn't have that property set. For example, a `company_name` property with fallback `"there"` could be used in a greeting: "Hello, " would render as "Hello, there" for contacts without a company set. No. The type is fixed at creation. If you need a different type, create a new property and migrate the values. Yes. When fetching a contact via the API, all property values are included in the response. # Registro.br Source: https://docs.sendkit.dev/knowledge-base/registro-br Aprenda como verificar seu domínio no SendKit usando o Registro.br. ## Pré-requisitos Antes de começar, tenha em mãos: 1. Uma [conta no SendKit](https://app.sendkit.dev/register) com um domínio adicionado 2. Acesso ao [painel do Registro.br](https://registro.br) 3. Os registros DNS do seu domínio, disponíveis na página de detalhes do domínio no SendKit ## Adicionar registros DNS Faça login no Registro.br, vá em **Meus Domínios**, clique no seu domínio, depois acesse **DNS > Editar zona**. ### 1. Registro DKIM Clique em **Nova entrada** e selecione o tipo **TXT**. No campo **Nome**, digite `sendkit._domainkey`. No campo **Dados**, cole o valor completo do DKIM da página de detalhes do domínio no SendKit. Clique em **Adicionar**. | Campo Registro.br | Valor SendKit | | ----------------- | ------------------------- | | Tipo | `TXT` | | Nome | `sendkit._domainkey` | | Dados | Seu valor DKIM do SendKit | ### 2. Registro SPF Clique em **Nova entrada** e selecione o tipo **TXT**. No campo **Nome**, digite `send`. No campo **Dados**, cole o valor SPF da página de detalhes do domínio no SendKit. Clique em **Adicionar**. | Campo Registro.br | Valor SendKit | | ----------------- | ------------------------ | | Tipo | `TXT` | | Nome | `send` | | Dados | Seu valor SPF do SendKit | ### 3. Registro MX Clique em **Nova entrada** e selecione o tipo **MX**. No campo **Nome**, digite `send`. No campo **Dados**, cole o valor MX da página de detalhes do domínio no SendKit. Defina a **Prioridade** como `10`. Clique em **Adicionar**. | Campo Registro.br | Valor SendKit | | ----------------- | ----------------------- | | Tipo | `MX` | | Nome | `send` | | Dados | Seu valor MX do SendKit | | Prioridade | `10` | ### 4. Registro DMARC (opcional) Clique em **Nova entrada** e selecione o tipo **TXT**. No campo **Nome**, digite `_dmarc`. No campo **Dados**, digite `v=DMARC1; p=none;`. Clique em **Adicionar**. Após adicionar todos os registros, clique em **Salvar** no topo da página para aplicar as alterações na zona DNS. ## Verificar seu domínio Volte à [página de detalhes do domínio no SendKit](https://app.sendkit.dev) e clique em **Refresh**. As alterações de DNS no Registro.br geralmente propagam em alguns minutos. Se a verificação não funcionar imediatamente, aguarde alguns minutos e tente novamente. O SendKit também verifica automaticamente em segundo plano. ## Solução de problemas O Registro.br só permite editar a zona DNS se o domínio estiver usando os servidores DNS do próprio Registro.br. Se você usa servidores DNS externos (como Cloudflare), adicione os registros lá. Certifique-se de clicar em **Salvar** no topo da página após adicionar todas as entradas. As alterações só são aplicadas depois de salvar a zona completa. O Registro.br suporta registros TXT longos. Cole o valor completo do DKIM sem quebrar em partes — o sistema aceita o valor inteiro. # AWS Route 53 Source: https://docs.sendkit.dev/knowledge-base/route53 Learn how to verify your domain on SendKit using AWS Route 53. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [AWS Management Console](https://console.aws.amazon.com/route53) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to the AWS Console, go to **Route 53 > Hosted zones**, and select your domain. Click **Create record** for each of the following. ### 1. DKIM record Click **Create record**. If using the wizard, switch to **Quick create record**. In the **Record name** field, enter `sendkit._domainkey`. Choose **TXT** from the Record type dropdown. In the **Value** field, paste the DKIM value from SendKit **wrapped in double quotes**. For example: `"v=DKIM1; k=rsa; p=..."`. Leave TTL as `3600` and click **Create records**. Route 53 requires TXT record values to be enclosed in **double quotes**. If you paste the value without quotes, the record will fail. | Route 53 field | SendKit value | | -------------- | ---------------------------------------------- | | Record name | `sendkit._domainkey` | | Record type | `TXT` | | Value | `"your DKIM value from SendKit"` (with quotes) | | TTL | `3600` | ### 2. SPF record Click **Create record**. Enter `send` in the **Record name** field. Choose **TXT**. Paste the SPF value from SendKit **wrapped in double quotes**. Leave TTL as `3600` and click **Create records**. | Route 53 field | SendKit value | | -------------- | --------------------------------------------- | | Record name | `send` | | Record type | `TXT` | | Value | `"your SPF value from SendKit"` (with quotes) | | TTL | `3600` | ### 3. MX record Click **Create record**. Enter `send` in the **Record name** field. Choose **MX**. Enter the priority followed by the MX value: `10 your-mx-value-from-sendkit`. Leave TTL as `3600` and click **Create records**. In Route 53, MX records combine the priority and value in one field. Enter `10` followed by a space, then the MX value from SendKit. | Route 53 field | SendKit value | | -------------- | ------------------------------- | | Record name | `send` | | Record type | `MX` | | Value | `10 your-mx-value-from-sendkit` | | TTL | `3600` | ### 4. DMARC record (optional) Click **Create record**. Enter `_dmarc`. Choose **TXT**. Enter `"v=DMARC1; p=none;"` (with quotes). Leave TTL as `3600` and click **Create records**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Route 53 DNS changes typically propagate within 60 seconds. If verification doesn't succeed immediately, wait a minute and try again. SendKit also checks automatically in the background. ## Troubleshooting Make sure your TXT values are wrapped in double quotes. Route 53 requires this for TXT records. Check the record in the console — the value should show with quotes. Route 53 combines priority and value in a single field. Enter `10 your-mx-value` — not just the hostname. The `10` is the priority. Make sure your domain's nameservers point to Route 53. If you registered the domain elsewhere, you need to update the nameservers at your registrar to the ones shown in Route 53. # Senders Source: https://docs.sendkit.dev/knowledge-base/senders Learn how to create and manage sender identities for your emails. ## What is a sender? A sender is a reusable identity that represents the "from" address on your emails. Instead of typing the full sender name, email, and reply-to address every time, you create a sender once and use it across campaigns, templates, and automations. A sender is made up of: | Field | Example | Description | | ------------ | --------------------- | --------------------------------------------------------------- | | **Name** | `Paulo from SendKit` | The display name recipients see in their inbox | | **Username** | `paulo` | The local part of the email address (before the @) | | **Domain** | `sendkit.dev` | A verified domain from your account | | **Reply-to** | `support@sendkit.dev` | Optional. Where replies go if different from the sender address | This produces a "from" address like: `Paulo from SendKit ` ## Creating a sender You can create senders from the [SendKit dashboard](https://app.sendkit.dev/senders). You need at least one verified domain before creating a sender. Go to **Domains** and verify your domain with the required DNS records. Go to **Senders** and click **Create Sender**. Fill in the name, username, and select your verified domain. Optionally set a reply-to address. Your sender is now available in campaigns, templates, and automations. ## Reply-to address The reply-to field is optional. When set, replies from recipients go to this address instead of the sender address. This is useful when: * Your sender address is a no-reply address (e.g., `notifications@yourdomain.com`) * You want replies to go to a shared inbox (e.g., `support@yourdomain.com`) * You use a different address for customer communication If left empty, replies go directly to the sender address. ## Using senders in the API When sending emails via the [API](/api-reference/endpoint/send-email), you pass the full "from" address directly — you don't reference a sender by ID. Senders are primarily used in the dashboard for campaigns, templates, and automations. The domain in the "from" address must be a verified domain in your account. Emails from unverified domains will be rejected. ## Deleting a sender A sender can only be deleted if it's not currently used by any campaign or template. If it's in use, you'll need to update those campaigns or templates to use a different sender first. ## FAQ Yes. You can create as many senders as you need on the same domain — for example, `support@yourdomain.com`, `notifications@yourdomain.com`, and `marketing@yourdomain.com`. Not on the same domain. Each username must be unique per domain. However, you can use the same username on different domains (e.g., `hello@domain-a.com` and `hello@domain-b.com`). Letters, numbers, dots, underscores, percent signs, plus signs, and hyphens. For example: `hello`, `no-reply`, `info.team`, `news+updates`. # SiteGround Source: https://docs.sendkit.dev/knowledge-base/siteground Learn how to verify your domain on SendKit using SiteGround DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [SiteGround Site Tools](https://tools.siteground.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to SiteGround, go to **Site Tools > Domain > DNS Zone Editor**. Select your domain and add each of the following records. ### 1. DKIM record In the DNS Zone Editor, select **TXT** from the record type tabs. In the **Name** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Click **Create**. | SiteGround field | SendKit value | | ---------------- | ---------------------------- | | Type | `TXT` | | Name | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | ### 2. SPF record Select **TXT** from the record type tabs. In the **Name** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Click **Create**. | SiteGround field | SendKit value | | ---------------- | --------------------------- | | Type | `TXT` | | Name | `send` | | Value | Your SPF value from SendKit | ### 3. MX record Select **MX** from the record type tabs. In the **Name** field, enter `send`. In the **Value** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Create**. | SiteGround field | SendKit value | | ---------------- | -------------------------- | | Type | `MX` | | Name | `send` | | Value | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Select **TXT** from the record type tabs. In the **Name** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Click **Create**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. SiteGround DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting The DNS Zone Editor is only available in **Site Tools**, not the older cPanel. Go to [tools.siteground.com](https://tools.siteground.com), select your site, then navigate to **Domain > DNS Zone Editor**. If your domain's nameservers don't point to SiteGround, DNS records added here won't take effect. Check your nameserver settings and add records at your active DNS provider. # SMTP Source: https://docs.sendkit.dev/knowledge-base/smtp Send emails using SendKit's SMTP relay instead of the REST API. ## What is SMTP sending? SendKit provides an SMTP relay that lets you send emails using standard SMTP protocol instead of the REST API. This is useful for applications, frameworks, and tools that already support SMTP out of the box — no SDK or HTTP integration needed. Emails sent via SMTP go through the same delivery pipeline as API-sent emails: domain verification, suppression checks, tracking, and event webhooks all work the same way. ## SMTP credentials | Setting | Value | | -------------- | -------------------------------------------------------- | | **Host** | `smtp.sendkit.dev` | | **Ports** | `465` (SSL), `587` (STARTTLS), `2587` (STARTTLS) | | **Username** | `sendkit` | | **Password** | Your API key (e.g., `sk_xxxxxxxx...`) | | **Encryption** | Implicit TLS on port 465, STARTTLS on ports 587 and 2587 | Your SMTP password is your API key. The same key you use for the REST API works for SMTP authentication. The permission level and domain scope of the key apply to SMTP as well. ## Port selection | Port | Protocol | When to use | | -------- | ------------------ | ------------------------------------------------------------------------ | | **465** | Implicit TLS (SSL) | Preferred for most applications. Connection is encrypted from the start | | **587** | STARTTLS | Standard submission port. Starts unencrypted, upgrades to TLS | | **2587** | STARTTLS | Alternative to 587 when your network or hosting provider blocks port 587 | All three ports deliver emails identically. Pick whichever one your application or network supports. ## Configuration examples In your `.env` file (Laravel 11+): ```env theme={null} MAIL_MAILER=smtp MAIL_HOST=smtp.sendkit.dev MAIL_PORT=465 MAIL_USERNAME=sendkit MAIL_PASSWORD=sk_your_api_key_here MAIL_SCHEME=smtps ``` If you're using port 587 (STARTTLS) instead: ```env theme={null} MAIL_MAILER=smtp MAIL_HOST=smtp.sendkit.dev MAIL_PORT=587 MAIL_USERNAME=sendkit MAIL_PASSWORD=sk_your_api_key_here MAIL_SCHEME=smtp ``` For Laravel 10 and earlier, use `MAIL_ENCRYPTION=ssl` (port 465) or `MAIL_ENCRYPTION=tls` (port 587) instead of `MAIL_SCHEME`. Using [Nodemailer](https://nodemailer.com): ```javascript theme={null} const transporter = nodemailer.createTransport({ host: "smtp.sendkit.dev", port: 465, secure: true, auth: { user: "sendkit", pass: "sk_your_api_key_here", }, }); await transporter.sendMail({ from: "you@yourdomain.com", to: "recipient@example.com", subject: "Hello from SendKit", html: "

Hello!

", }); ```
Using Django in `settings.py`: ```python theme={null} EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" EMAIL_HOST = "smtp.sendkit.dev" EMAIL_PORT = 465 EMAIL_USE_SSL = True EMAIL_HOST_USER = "sendkit" EMAIL_HOST_PASSWORD = "sk_your_api_key_here" ``` Using `smtplib` directly: ```python theme={null} import smtplib from email.mime.text import MIMEText msg = MIMEText("

Hello!

", "html") msg["Subject"] = "Hello from SendKit" msg["From"] = "you@yourdomain.com" msg["To"] = "recipient@example.com" with smtplib.SMTP_SSL("smtp.sendkit.dev", 465) as server: server.login("sendkit", "sk_your_api_key_here") server.send_message(msg) ```
Using [PHPMailer](https://github.com/PHPMailer/PHPMailer): ```php theme={null} use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\SMTP; $mail = new PHPMailer(true); $mail->isSMTP(); $mail->Host = 'smtp.sendkit.dev'; $mail->SMTPAuth = true; $mail->Username = 'sendkit'; $mail->Password = 'sk_your_api_key_here'; $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; $mail->Port = 465; $mail->setFrom('you@yourdomain.com'); $mail->addAddress('recipient@example.com'); $mail->Subject = 'Hello from SendKit'; $mail->isHTML(true); $mail->Body = '

Hello!

'; $mail->send(); ```
Using Action Mailer in `config/environments/production.rb`: ```ruby theme={null} config.action_mailer.smtp_settings = { address: "smtp.sendkit.dev", port: 465, user_name: "sendkit", password: "sk_your_api_key_here", ssl: true } ``` Using `net/smtp` directly: ```ruby theme={null} require "net/smtp" message = "From: you@yourdomain.com\r\n" \ "To: recipient@example.com\r\n" \ "Subject: Hello from SendKit\r\n" \ "Content-Type: text/html\r\n" \ "\r\n" \ "

Hello!

" smtp = Net::SMTP.new("smtp.sendkit.dev", 465) smtp.enable_tls smtp.start("smtp.sendkit.dev", "sendkit", "sk_your_api_key_here", :login) do |s| s.send_message(message, "you@yourdomain.com", "recipient@example.com") end ```
Using [go-mail](https://github.com/wneessen/go-mail): ```go theme={null} package main import ( "log" "github.com/wneessen/go-mail" ) func main() { m := mail.NewMsg() m.From("you@yourdomain.com") m.To("recipient@example.com") m.Subject("Hello from SendKit") m.SetBodyString(mail.TypeTextHTML, "

Hello!

") c, err := mail.NewClient("smtp.sendkit.dev", mail.WithPort(465), mail.WithSMTPAuth(mail.SMTPAuthLogin), mail.WithSSLPort(false), mail.WithTLSPortPolicy(mail.TLSMandatory), mail.WithUsername("sendkit"), mail.WithPassword("sk_your_api_key_here"), ) if err != nil { log.Fatal(err) } if err := c.DialAndSend(m); err != nil { log.Fatal(err) } } ```
Using [Jakarta Mail](https://jakartaee.github.io/mail-api/): ```java theme={null} import jakarta.mail.*; import jakarta.mail.internet.*; import java.util.Properties; Properties props = new Properties(); props.put("mail.smtp.host", "smtp.sendkit.dev"); props.put("mail.smtp.port", "465"); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.ssl.enable", "true"); Session session = Session.getInstance(props, new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("sendkit", "sk_your_api_key_here"); } }); Message message = new MimeMessage(session); message.setFrom(new InternetAddress("you@yourdomain.com")); message.setRecipient(Message.RecipientType.TO, new InternetAddress("recipient@example.com")); message.setSubject("Hello from SendKit"); message.setContent("

Hello!

", "text/html"); Transport.send(message); ```
Using [lettre](https://crates.io/crates/lettre): ```rust theme={null} use lettre::{ message::header::ContentType, transport::smtp::authentication::Credentials, Message, SmtpTransport, Transport, }; let email = Message::builder() .from("you@yourdomain.com".parse().unwrap()) .to("recipient@example.com".parse().unwrap()) .subject("Hello from SendKit") .header(ContentType::TEXT_HTML) .body("

Hello!

".to_string()) .unwrap(); let creds = Credentials::new( "sendkit".to_string(), "sk_your_api_key_here".to_string(), ); let mailer = SmtpTransport::relay("smtp.sendkit.dev") .unwrap() .credentials(creds) .build(); mailer.send(&email).unwrap(); ```
Using [Swoosh](https://hex.pm/packages/swoosh) with the SMTP adapter: ```elixir theme={null} # config/config.exs config :my_app, MyApp.Mailer, adapter: Swoosh.Adapters.SMTP, relay: "smtp.sendkit.dev", port: 465, username: "sendkit", password: "sk_your_api_key_here", ssl: true, tls: :never, auth: :always # lib/my_app/mailer.ex defmodule MyApp.Mailer do use Swoosh.Mailer, otp_app: :my_app end # Sending an email import Swoosh.Email new() |> to("recipient@example.com") |> from("you@yourdomain.com") |> subject("Hello from SendKit") |> html_body("

Hello!

") |> MyApp.Mailer.deliver() ```
Using [MailKit](https://github.com/jstedfast/MailKit): ```csharp theme={null} using MailKit.Net.Smtp; using MailKit.Security; using MimeKit; var message = new MimeMessage(); message.From.Add(new MailboxAddress("", "you@yourdomain.com")); message.To.Add(new MailboxAddress("", "recipient@example.com")); message.Subject = "Hello from SendKit"; message.Body = new TextPart("html") { Text = "

Hello!

" }; using var client = new SmtpClient(); await client.ConnectAsync("smtp.sendkit.dev", 465, SecureSocketOptions.SslOnConnect); await client.AuthenticateAsync("sendkit", "sk_your_api_key_here"); await client.SendAsync(message); await client.DisconnectAsync(true); ```
Using the [WP Mail SMTP](https://wordpress.org/plugins/wp-mail-smtp/) plugin: | Setting | Value | | ------------- | ------------------ | | SMTP Host | `smtp.sendkit.dev` | | Encryption | SSL | | SMTP Port | `465` | | SMTP Username | `sendkit` | | SMTP Password | Your API key |
## SMTP vs API | Feature | SMTP | API | | --------------------- | ------------------------------------- | -------------------------------- | | **Setup** | Works with any app that supports SMTP | Requires HTTP integration or SDK | | **Bulk sending** | One email per SMTP session | Up to 100 emails per request | | **Attachments** | Native MIME attachments | Base64-encoded in JSON | | **Templates** | Not supported | Supported via `template.id` | | **Scheduled sending** | Not supported | Supported via `scheduled_at` | | **Tags** | Not supported | Supported via `tags` | Use the REST API when you need features like templates, scheduled sending, tags, or bulk sending. Use SMTP when you want a drop-in integration with existing applications. ## FAQ Yes. Any valid API key works as the SMTP password. The key's permission level and domain scope are enforced — a send-only key scoped to a specific domain will only be able to send from that domain via SMTP. Some hosting providers (AWS, GCP, Azure) block outbound port 587 by default. Use port 465 (SSL) or 2587 (alternative STARTTLS) instead. Yes. Open tracking, click tracking, and all webhook events (delivered, bounced, opened, clicked, etc.) work the same way as API-sent emails. SMTP sending follows the same rate limits as the REST API based on your plan. Each SMTP message counts as one email toward your quota. # Squarespace Source: https://docs.sendkit.dev/knowledge-base/squarespace Learn how to verify your domain on SendKit using Squarespace DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Squarespace account](https://account.squarespace.com) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Squarespace, go to **Domains**, select your domain, then click **DNS > DNS Settings**. Click **Add Record** for each of the following. ### 1. DKIM record Click **Add Record** and select **TXT** as the record type. In the **Host** field, enter `sendkit._domainkey`. In the **Data** field, paste the full DKIM value from your SendKit domain detail page. Click **Add**. | Squarespace field | SendKit value | | ----------------- | ---------------------------- | | Record type | `TXT` | | Host | `sendkit._domainkey` | | Data | Your DKIM value from SendKit | ### 2. SPF record Click **Add Record** and select **TXT** as the record type. In the **Host** field, enter `send`. In the **Data** field, paste the SPF value from your SendKit domain detail page. Click **Add**. | Squarespace field | SendKit value | | ----------------- | --------------------------- | | Record type | `TXT` | | Host | `send` | | Data | Your SPF value from SendKit | ### 3. MX record Click **Add Record** and select **MX** as the record type. In the **Host** field, enter `send`. In the **Data** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Add**. | Squarespace field | SendKit value | | ----------------- | -------------------------- | | Record type | `MX` | | Host | `send` | | Data | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Click **Add Record** and select **TXT** as the record type. In the **Host** field, enter `_dmarc`. In the **Data** field, enter `v=DMARC1; p=none;`. Click **Add**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Squarespace DNS changes can take up to 30 minutes to propagate. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting These instructions only apply if Squarespace manages your DNS. If you transferred your domain to Squarespace but use external nameservers, add the records at your DNS provider instead. Squarespace supports TXT and MX records. If you don't see these options, make sure your domain is using Squarespace's built-in DNS. # Strato Source: https://docs.sendkit.dev/knowledge-base/strato Learn how to verify your domain on SendKit using Strato DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Strato customer area](https://www.strato.com/apps/CustomerService) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Strato, go to **Domains > Domain Management**, select your domain, then click **DNS Settings**. Add each of the following records. ### 1. DKIM record In the DNS settings, find the **TXT Records** section. Set the **Subdomain** to `sendkit._domainkey`. Paste the full DKIM value from your SendKit domain detail page. Click **Save** or **Accept**. | Strato field | SendKit value | | ------------ | ---------------------------- | | Type | `TXT` | | Subdomain | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | ### 2. SPF record In the **TXT Records** section, set the **Subdomain** to `send`. Paste the SPF value from your SendKit domain detail page. Click **Save** or **Accept**. | Strato field | SendKit value | | ------------ | --------------------------- | | Type | `TXT` | | Subdomain | `send` | | Value | Your SPF value from SendKit | ### 3. MX record In the DNS settings, find the **MX Records** section. Set the **Subdomain** to `send`. Paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Save** or **Accept**. | Strato field | SendKit value | | ------------ | -------------------------- | | Type | `MX` | | Subdomain | `send` | | Mail server | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) In the **TXT Records** section, set the **Subdomain** to `_dmarc`. Enter `v=DMARC1; p=none;`. Click **Save** or **Accept**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Strato DNS changes can take up to 30 minutes to propagate. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Strato's DNS interface is more limited than some providers. If you can't find the option to add TXT or MX records, make sure you're in **DNS Settings** (not email settings) and check that your hosting plan supports custom DNS records. Strato DNS propagation can be slower than other providers. If records aren't detected after 30 minutes, wait up to 2 hours before contacting support. # Suppression List Source: https://docs.sendkit.dev/knowledge-base/suppression-list SendKit automatically manages your suppression list so you never send to bad addresses. Zero configuration required. ## Automatic list hygiene, built in Most email providers leave bounce handling, complaint tracking, and list cleaning up to you. You have to monitor delivery events, build logic to track failures, update your database, and remember to check before every send. **SendKit does all of this automatically.** Every bounce, every spam complaint, every unreachable address is tracked and suppressed for you — with zero configuration and zero code. Just send your emails and let SendKit protect your reputation. You don't need to build any bounce handling logic. SendKit's suppression list works out of the box for every email you send — via API, campaigns, or automations. ## What SendKit handles for you ### Hard bounces — suppressed instantly When an email permanently bounces (mailbox doesn't exist, domain is invalid, recipient server permanently rejects), SendKit **immediately and permanently suppresses** that address. You'll never accidentally send to it again. No webhook handler to build. No database to update. It just works. ### Soft bounces — smart threshold detection Soft bounces are temporary failures — a full mailbox, a server temporarily down. SendKit doesn't suppress on the first soft bounce. Instead, it tracks them intelligently: * **1st or 2nd soft bounce** — Address stays active, SendKit keeps trying * **3rd soft bounce** — Address is automatically suppressed * **Successful delivery after a soft bounce** — Counter resets to zero This means transient issues don't block legitimate recipients, but consistently unreachable addresses are automatically cleaned up. ### Spam complaints — immediate protection When a recipient marks your email as spam, SendKit **immediately suppresses** their address. This is critical — continuing to send to people who complained is the fastest way to destroy your sender reputation and land in spam folders. ### Automatic enforcement on every send Every email you send through SendKit — whether it's a single API call, a batch send, a campaign, or an automation — is automatically checked against your suppression list. Suppressed addresses are blocked before they ever reach the email provider. You don't need to query the list yourself. SendKit handles it. ## Manual suppressions You can also manually suppress addresses through the [API](/api-reference/endpoint/create-suppression) or the dashboard. This is useful for: * Honoring unsubscribe requests * Removing known bad addresses before a campaign * Proactively blocking addresses you know are invalid ## Suppression reasons Each entry has a reason so you always know why an address was suppressed: | Reason | Description | Added by | | ----------- | ------------------------------- | --------- | | `bounce` | Hard bounce, or 3+ soft bounces | Automatic | | `complaint` | Recipient marked as spam | Automatic | | `manual` | Added via API or dashboard | You | ## Removing a suppression You can remove an address from the suppression list through the [API](/api-reference/endpoint/delete-suppression) or the dashboard. Be careful when removing addresses suppressed for hard bounces or spam complaints. Sending to them again will likely produce the same result and can damage your reputation. ## FAQ No. That's the point. SendKit handles bounces, complaints, and list hygiene automatically. You just send emails. Yes. The suppression list is per-team. All team members and API keys share the same list. Yes. When sending a campaign, SendKit automatically skips any contacts on the suppression list. These contacts are not counted against your sending volume. No. It only means SendKit will attempt delivery again. If the underlying problem persists (invalid mailbox, full inbox), the address may be re-suppressed automatically. You can add addresses one at a time through the API. Going forward, SendKit will automatically maintain the list for you. # Templates Source: https://docs.sendkit.dev/knowledge-base/templates Design reusable email templates with a visual editor and dynamic personalization. ## What are templates? Templates are reusable email designs that you use in campaigns, automations, and test sends. Instead of writing HTML from scratch every time, you build a template once and reuse it wherever you need it. Each template stores the subject line, sender, HTML body, and plain text version — along with any personalization variables. ## Creating a template Go to **Templates** and click **Create Template**. A new draft template is created with a default name, and you're taken straight to the editor. ## The editor SendKit uses a visual editor where you type and format content directly — no HTML knowledge needed. Type `/` to open the command menu and insert any block. ### Available blocks Paragraph, Heading 1–3, Bullet list, Numbered list, Quote, Code block, Link Image (upload), YouTube embed, X/Twitter embed Button (CTA), Divider, Section, Social links Raw HTML, Variable ### Auto-save The editor saves automatically as you type. You'll see a save indicator in the header — no need to manually save. ### Template settings In the editor sidebar, you can configure: | Field | Description | | ------------ | ----------------------------------------------------------------------- | | **Name** | Internal name for organizing templates (recipients don't see this) | | **Subject** | Email subject line. Supports variables like `{{FIRST_NAME}}` | | **From** | Select a [sender](/knowledge-base/senders) to use as the "from" address | | **Reply-To** | Optional reply-to email address | ## Personalization variables Templates support dynamic variables that are replaced with each recipient's data when the email is sent. ### Built-in variables | Variable | Replaced with | | ---------------- | ---------------------------- | | `{{EMAIL}}` | Contact's email address | | `{{FIRST_NAME}}` | Contact's first name | | `{{LAST_NAME}}` | Contact's last name | | `{{FULL_NAME}}` | First and last name combined | | `{{USER_ID}}` | Contact's user ID | ### Custom variables Any [property](/knowledge-base/properties) you create is automatically available as a variable. For example, a property with key `company_name` becomes `{{COMPANY_NAME}}`. ### Fallback values Each variable can have a fallback value — used when the contact doesn't have that data set. For example, `{{FIRST_NAME}}` with fallback `"there"` renders as "Hello, there" for contacts without a first name. Variables work in both the **subject line** and the **template body**. You can add up to 50 variables per template. ## Publishing Templates have two statuses: | Status | Description | | ------------- | ---------------------------------------------------------------------- | | **Draft** | Work in progress. Can be edited freely but cannot be used in campaigns | | **Published** | Ready to use. Can be selected when creating campaigns and automations | Click **Publish** in the editor header to change a draft to published. You can unpublish at any time. ## Preview and test ### Preview The template detail page has three tabs: * **Preview** — Rendered HTML as recipients will see it * **HTML** — Raw HTML source code with copy button * **Plain Text** — Auto-generated plain text version ### Send a test email Click **Send test email** from the template detail page or editor. Enter a recipient email (defaults to your own) and optionally fill in variable values to see how personalization looks. Test emails have "\[Test]" prefixed to the subject line so you can easily identify them in your inbox. ## Folders Folders let you organize templates into groups. For example, you might create folders for "Onboarding", "Newsletter", or "Transactional". ### Creating a folder Click the folder icon button next to **Create Template** in the top right. Enter a name and click **Create folder**. The folder appears as a tab in the template list. ### Browsing folders The template list shows horizontal tabs for filtering: * **All templates** shows every template regardless of folder * Each folder tab shows only templates in that folder, with a count * **Unassigned** shows templates that aren't in any folder ### Moving templates to a folder Open the template's dropdown menu (three dots) and select **Move to folder**, then choose the destination. To remove a template from a folder, select **Remove from folder** from the same menu. ### Renaming and deleting folders Hover over a folder tab to reveal the options button. Click it to rename or delete the folder. Deleting a folder does not delete the templates inside it — they become unassigned. Folder names must be unique within your team. Duplicating a template preserves its folder assignment. ## Duplicating a template Click **Duplicate** from the template dropdown menu. A copy is created with "(Copy)" appended to the name. The duplicate starts as a **Draft** regardless of the original's status. All content, variables, sender, and settings are copied — except images. ## Deleting a template A template can be deleted if it's not used by any unsent campaign (draft, scheduled, or sending) or active/paused automation. Templates used only by already-sent campaigns can be deleted. Deleted templates are soft-deleted — the data is preserved for email history. Sent campaigns and emails still reference the original template. ## Images You can upload images directly in the editor. Images are stored and served by SendKit — no need for external hosting. Maximum file size is **5 MB** per image. ## Using templates in campaigns and automations When creating a [campaign](/knowledge-base/campaigns) or an [automation](/knowledge-base/automations) email step, you select a published template. The template's subject, sender, and body are used, with variables replaced per contact at send time. ## FAQ No. The visual editor lets you build emails by typing and using the slash command menu. For advanced users, you can insert raw HTML blocks if needed. Yes, but changes won't affect emails that were already sent. Sent emails store a snapshot of the template at the time of sending. Yes. SendKit automatically generates a plain text version from your HTML content. You don't need to create it manually. There's no limit. Create as many templates as you need. Yes. Templates are reusable — you can select the same template for any number of campaigns and automations. The templates become unassigned — they're not deleted. You can find them in the "Unassigned" tab and move them to another folder. No. Folders are a single level. There are no subfolders. # Vercel Source: https://docs.sendkit.dev/knowledge-base/vercel Learn how to verify your domain on SendKit using Vercel DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Vercel dashboard](https://vercel.com/dashboard) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Vercel, go to your project's **Settings > Domains**, select your domain, then click the **DNS Records** tab. Click **Add Record** for each of the following. ### 1. DKIM record Click **Add Record** and select **TXT** as the type. In the **Name** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Click **Add**. | Vercel field | SendKit value | | ------------ | ---------------------------- | | Type | `TXT` | | Name | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | ### 2. SPF record Click **Add Record** and select **TXT** as the type. In the **Name** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Click **Add**. | Vercel field | SendKit value | | ------------ | --------------------------- | | Type | `TXT` | | Name | `send` | | Value | Your SPF value from SendKit | ### 3. MX record Click **Add Record** and select **MX** as the type. In the **Name** field, enter `send`. In the **Value** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Click **Add**. | Vercel field | SendKit value | | ------------ | -------------------------- | | Type | `MX` | | Name | `send` | | Value | Your MX value from SendKit | | Priority | `10` | ### 4. DMARC record (optional) Click **Add Record** and select **TXT** as the type. In the **Name** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Click **Add**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Vercel DNS changes typically propagate within a few minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting Vercel DNS only works if your domain's nameservers are pointed to Vercel. If you're using Vercel for hosting but another provider for DNS, add the records at that DNS provider instead. The DNS Records tab is only available for domains using Vercel as the DNS provider. Check your domain's nameserver configuration. # Webhooks Source: https://docs.sendkit.dev/knowledge-base/webhooks Receive real-time notifications about email and contact events as they happen. ## What are webhooks? Webhooks let your application receive real-time HTTP notifications when something happens with your emails — a delivery, a bounce, a click, a spam complaint. Instead of polling the API, SendKit pushes events directly to your server. You configure an endpoint URL, choose which events you care about, and SendKit sends a `POST` request every time one of those events occurs. ## Getting started Go to **Webhooks** in the dashboard and click **Create Webhook**. You'll need to provide an endpoint URL and select the events you want to receive. SendKit verifies your endpoint is reachable before creating the webhook. ## Key features * **Signed requests** — Every delivery includes an HMAC-SHA256 signature so you can verify it's from SendKit * **Automatic retries** — Failed deliveries are attempted up to 3 times with 60-second intervals * **Auto-pause** — Webhooks are automatically paused after 5 consecutive failures to protect your server * **Event replay** — Re-send any past event from the dashboard for debugging or recovery * **Real-time logs** — View every delivery with its payload, response, and status ## Learn more How webhooks work and payload format. All available email and contact events. Retry behavior, auto-pause, and best practices. HMAC-SHA256 verification with code examples. # Wix Source: https://docs.sendkit.dev/knowledge-base/wix Learn how to verify your domain on SendKit using Wix DNS. ## Prerequisites Before you begin, make sure you have: 1. A [SendKit account](https://app.sendkit.dev/register) with a domain added 2. Access to your [Wix account](https://www.wix.com/account/domains) 3. Your domain's DNS records from the SendKit domain detail page ## Add DNS records Log in to Wix, go to **Account > Domains**, click your domain, then select **DNS Records**. Click **Add Record** for each of the following. ### 1. DKIM record Click **Add Record** and select **TXT** as the record type. In the **Host Name** field, enter `sendkit._domainkey`. In the **Value** field, paste the full DKIM value from your SendKit domain detail page. Leave TTL as `3600` and click **Save**. | Wix field | SendKit value | | --------- | ---------------------------- | | Type | `TXT` | | Host Name | `sendkit._domainkey` | | Value | Your DKIM value from SendKit | | TTL | `3600` | ### 2. SPF record Click **Add Record** and select **TXT**. In the **Host Name** field, enter `send`. In the **Value** field, paste the SPF value from your SendKit domain detail page. Leave TTL as `3600` and click **Save**. | Wix field | SendKit value | | --------- | --------------------------- | | Type | `TXT` | | Host Name | `send` | | Value | Your SPF value from SendKit | | TTL | `3600` | ### 3. MX record Click **Add Record** and select **MX**. In the **Host Name** field, enter `send`. In the **Points to** field, paste the MX value from your SendKit domain detail page. Set **Priority** to `10`. Leave TTL as `3600` and click **Save**. | Wix field | SendKit value | | --------- | -------------------------- | | Type | `MX` | | Host Name | `send` | | Points to | Your MX value from SendKit | | Priority | `10` | | TTL | `3600` | ### 4. DMARC record (optional) Click **Add Record** and select **TXT**. In the **Host Name** field, enter `_dmarc`. In the **Value** field, enter `v=DMARC1; p=none;`. Leave TTL as `3600` and click **Save**. ## Verify your domain Go back to your [SendKit domain detail page](https://app.sendkit.dev) and click **Refresh**. Wix DNS changes can take up to 48 hours to propagate, though most changes are visible within 30 minutes. If verification doesn't succeed immediately, wait a few minutes and try again. SendKit also checks automatically in the background. ## Troubleshooting If your domain is connected to Wix via nameservers from another provider, you need to add the DNS records at that provider instead. Wix DNS management only works when using Wix nameservers. Go to **Account > Domains** (not the site editor). Click your domain name, then look for the **DNS Records** tab. This is separate from the domain connection settings. The SendKit MX record goes on the `send` subdomain. It won't conflict with Wix email or any existing MX records on your root domain. # .NET Source: https://docs.sendkit.dev/sdks/dotnet Send emails from C# and .NET using the SendKit SDK. View on GitHub View on NuGet ## Install ```bash theme={null} dotnet add package SendKit ``` ## Send email ```csharp theme={null} using SendKit; var client = new SendKitClient("sk_your_api_key"); var response = await client.Emails.SendAsync(new SendEmailParams { From = "Your Name ", To = ["recipient@example.com"], Subject = "Hello from SendKit", Html = "

Welcome!

Your first email with SendKit.

" }); Console.WriteLine($"Email sent: {response.Id}"); ``` # Elixir Source: https://docs.sendkit.dev/sdks/elixir Send emails from Elixir using the SendKit SDK. View on GitHub View on Hex ## Install Add to your `mix.exs` dependencies: ```elixir theme={null} def deps do [ {:sendkit, "~> 1.0"} ] end ``` Then run: ```bash theme={null} mix deps.get ``` ## Send email ```elixir theme={null} client = SendKit.new("sk_your_api_key") {:ok, %{"id" => id}} = SendKit.Emails.send(client, %{ from: "Your Name ", to: ["recipient@example.com"], subject: "Hello from SendKit", html: "

Welcome!

Your first email with SendKit.

" }) IO.puts("Email sent: #{id}") ``` # Go Source: https://docs.sendkit.dev/sdks/go Send emails from Go using the SendKit SDK. View on GitHub View on pkg.go.dev ## Install ```bash theme={null} go get github.com/sendkitdev/sendkit-go ``` ## Send email ```go theme={null} package main import ( "context" "fmt" sendkit "github.com/sendkitdev/sendkit-go" ) func main() { client, _ := sendkit.NewClient("sk_your_api_key") resp, _ := client.Emails.Send(context.Background(), &sendkit.SendEmailParams{ From: "Your Name ", To: []string{"recipient@example.com"}, Subject: "Hello from SendKit", HTML: "

Welcome!

Your first email with SendKit.

", }) fmt.Println("Email sent:", resp.ID) } ``` # Java Source: https://docs.sendkit.dev/sdks/java Send emails from Java using the SendKit SDK. View on GitHub View on Maven Central ## Install ```xml Maven theme={null} dev.sendkit sendkit 1.0.0 ``` ```groovy Gradle theme={null} implementation 'dev.sendkit:sendkit:1.0.0' ``` ## Send email ```java theme={null} import dev.sendkit.SendKit; import dev.sendkit.Emails; import java.util.List; SendKit client = new SendKit("sk_your_api_key"); Emails.SendEmailResponse response = client.emails().send( new Emails.SendEmailParams( "Your Name ", List.of("recipient@example.com"), "Hello from SendKit" ).html("

Welcome!

Your first email with SendKit.

") ); System.out.println("Email sent: " + response.getId()); ``` # Laravel Source: https://docs.sendkit.dev/sdks/laravel Integrate SendKit with Laravel using the official package. View on GitHub View on Packagist ## Install ```bash theme={null} composer require sendkit/sendkit-laravel ``` ## Configure Add your API key to your `.env` file: ```bash .env theme={null} SENDKIT_API_KEY=sk_your_api_key ``` ## Send email ### Using the Laravel Mail driver SendKit integrates with Laravel's built-in Mail system. Just set the mailer in your `.env`: ```bash .env theme={null} MAIL_MAILER=sendkit ``` That's it. Send emails using Laravel's standard `Mail` facade as usual: ```php theme={null} use App\Mail\WelcomeEmail; use Illuminate\Support\Facades\Mail; Mail::to('recipient@example.com')->send(new WelcomeEmail()); ``` ### Using the SendKit facade If you need more control, you can use the SendKit facade directly: ```php theme={null} use SendKit\Laravel\Facades\SendKit; $response = SendKit::emails()->send([ 'from' => 'Your Name ', 'to' => 'recipient@example.com', 'subject' => 'Hello from SendKit', 'html' => '

Welcome!

Your first email with SendKit.

', ]); echo $response['id']; ``` ## Validate email Validate an email address before sending. Each validation costs credits. ```php theme={null} use SendKit\Laravel\Facades\SendKit; $result = SendKit::validateEmail('recipient@example.com'); if ($result['should_block']) { // Email should not be used echo $result['block_reason']; } echo $result['is_valid']; // "HIGH" or "LOW" echo $result['evaluations']; // detailed checks ``` The `evaluations` array contains: | Key | Description | | ------------------ | ------------------------------------------------ | | `has_valid_syntax` | Whether the email has valid syntax | | `has_valid_dns` | Whether the domain has valid DNS records | | `mailbox_exists` | Whether the mailbox exists | | `is_role_address` | Whether it's a role address (e.g. info@, admin@) | | `is_disposable` | Whether it's a disposable email | | `is_random_input` | Whether it appears to be random input | ## Contacts ### Create or update a contact Create a new contact or update an existing one if the email already exists (upsert). ```php theme={null} use SendKit\Laravel\Facades\SendKit; $contact = SendKit::contacts()->create([ 'email' => 'john@example.com', 'first_name' => 'John', 'last_name' => 'Doe', 'list_ids' => ['list-uuid-1', 'list-uuid-2'], 'properties' => ['COMPANY' => 'Acme'], ]); echo $contact['id']; ``` ### List contacts Retrieve a paginated list of contacts. ```php theme={null} $contacts = SendKit::contacts()->list(); // With pagination $contacts = SendKit::contacts()->list(['page' => 2]); echo $contacts['meta']['total']; // total contacts ``` ### Get a contact ```php theme={null} $contact = SendKit::contacts()->get('contact-uuid'); echo $contact['email']; echo $contact['properties']['COMPANY']; ``` ### Update a contact ```php theme={null} $contact = SendKit::contacts()->update('contact-uuid', [ 'first_name' => 'Johnny', 'unsubscribed' => true, ]); ``` ### Delete a contact ```php theme={null} SendKit::contacts()->delete('contact-uuid'); ``` ### Add a contact to lists ```php theme={null} $contact = SendKit::contacts()->addToLists('contact-uuid', [ 'list-uuid-1', 'list-uuid-2', ]); ``` ### List a contact's lists ```php theme={null} $lists = SendKit::contacts()->listLists('contact-uuid'); // With pagination $lists = SendKit::contacts()->listLists('contact-uuid', ['page' => 2]); ``` ### Remove a contact from a list ```php theme={null} SendKit::contacts()->removeFromList('contact-uuid', 'list-uuid'); ``` ## Contact properties Contact properties let you define custom fields for your contacts. ### Create a property ```php theme={null} use SendKit\Laravel\Facades\SendKit; $property = SendKit::contactProperties()->create([ 'key' => 'company', 'type' => 'string', // "string", "number", or "date" 'fallback_value' => 'N/A', // optional ]); echo $property['id']; ``` ### List properties ```php theme={null} $properties = SendKit::contactProperties()->list(); // With pagination $properties = SendKit::contactProperties()->list(['page' => 2]); ``` ### Update a property ```php theme={null} $property = SendKit::contactProperties()->update('property-uuid', [ 'key' => 'organization', 'fallback_value' => 'Unknown', ]); ``` ### Delete a property ```php theme={null} SendKit::contactProperties()->delete('property-uuid'); ``` A `SendKitException` with status `409` is thrown if the property is used in segment filters. ## Webhooks The package automatically registers a `POST /webhook/sendkit` route in your application — no extra setup needed. When SendKit sends a webhook to this endpoint, the package verifies the signature and dispatches a Laravel event you can listen to. ### Add your webhook secret To verify that incoming webhooks are actually from SendKit, add your webhook secret to `.env`: ```bash .env theme={null} SENDKIT_WEBHOOK_SECRET=your-webhook-secret ``` You can find your webhook secret in the [SendKit dashboard](https://app.sendkit.dev). When a secret is configured, every incoming request is verified using HMAC-SHA256. If the signature doesn't match, the request is rejected with a `403` response. If no secret is configured, signature verification is skipped. We strongly recommend always setting a secret in production. ### Customizing the webhook path By default the webhook listens at `/webhook/sendkit`. You can change this with an environment variable: ```bash .env theme={null} SENDKIT_WEBHOOK_PATH=api/webhooks/sendkit ``` This will register the route at `POST /api/webhooks/sendkit` instead. Make sure to update the webhook URL in your SendKit dashboard to match. ### Listening for events When a webhook is received, the package dispatches a Laravel event based on the event type. You can listen for these events anywhere you normally would — in a listener, a service provider, or an `EventServiceProvider`: ```php theme={null} use SendKit\Laravel\Events\EmailDelivered; use Illuminate\Support\Facades\Event; Event::listen(EmailDelivered::class, function ($event) { $emailId = $event->payload['email_id']; // Handle the delivered email }); ``` Every event has a `payload` property with the webhook data sent by SendKit. ### Available events | Event class | Webhook type | Triggered when | | ---------------------- | ------------------------ | ------------------------------------ | | `EmailSent` | `email.sent` | Email accepted for delivery | | `EmailDelivered` | `email.delivered` | Email delivered to recipient | | `EmailBounced` | `email.bounced` | Email bounced | | `EmailComplained` | `email.complained` | Recipient marked as spam | | `EmailOpened` | `email.opened` | Recipient opened the email | | `EmailClicked` | `email.clicked` | Recipient clicked a link | | `EmailFailed` | `email.failed` | Email failed to send | | `EmailDeliveryDelayed` | `email.delivery_delayed` | Delivery is taking longer than usual | | `EmailRejected` | `email.rejected` | Email was rejected | | `ContactCreated` | `contact.created` | Contact was created | | `ContactUpdated` | `contact.updated` | Contact was updated | | `ContactDeleted` | `contact.deleted` | Contact was deleted | All event classes are in the `SendKit\Laravel\Events` namespace. ### Advanced configuration For full control over the webhook configuration, publish the config file: ```bash theme={null} php artisan vendor:publish --tag=sendkit-config ``` This creates a `config/sendkit.php` file where you can customize the webhook path, secret, and other options. # Node.js Source: https://docs.sendkit.dev/sdks/node Send emails from Node.js using the SendKit SDK. View on GitHub View on npm ## Install ```bash npm theme={null} npm install @sendkitdev/sdk ``` ```bash yarn theme={null} yarn add @sendkitdev/sdk ``` ```bash pnpm theme={null} pnpm add @sendkitdev/sdk ``` ## Send email ```typescript theme={null} import { SendKit } from '@sendkitdev/sdk'; const sendkit = new SendKit('sk_your_api_key'); const { data, error } = await sendkit.emails.send({ from: 'Your Name ', to: 'recipient@example.com', subject: 'Hello from SendKit', html: '

Welcome!

Your first email with SendKit.

', }); if (error) { console.error(error); } else { console.log('Email sent:', data.id); } ``` # PHP Source: https://docs.sendkit.dev/sdks/php Send emails from PHP using the SendKit SDK. View on GitHub View on Packagist ## Install ```bash theme={null} composer require sendkit/sendkit-php ``` ## Send email ```php theme={null} use SendKit\SendKit; $client = SendKit::client('sk_your_api_key'); $response = $client->emails()->send([ 'from' => 'Your Name ', 'to' => 'recipient@example.com', 'subject' => 'Hello from SendKit', 'html' => '

Welcome!

Your first email with SendKit.

', ]); echo $response['id']; ``` ## Validate email Validate an email address before sending. Each validation costs credits. ```php theme={null} use SendKit\SendKit; $client = SendKit::client('sk_your_api_key'); $result = $client->validateEmail('recipient@example.com'); if ($result['should_block']) { // Email should not be used echo $result['block_reason']; } echo $result['is_valid']; // "HIGH" or "LOW" echo $result['evaluations']; // detailed checks ``` The `evaluations` array contains: | Key | Description | | ------------------ | ------------------------------------------------ | | `has_valid_syntax` | Whether the email has valid syntax | | `has_valid_dns` | Whether the domain has valid DNS records | | `mailbox_exists` | Whether the mailbox exists | | `is_role_address` | Whether it's a role address (e.g. info@, admin@) | | `is_disposable` | Whether it's a disposable email | | `is_random_input` | Whether it appears to be random input | ## Contacts ### Create or update a contact Create a new contact or update an existing one if the email already exists (upsert). ```php theme={null} $contact = $client->contacts()->create([ 'email' => 'john@example.com', 'first_name' => 'John', 'last_name' => 'Doe', 'list_ids' => ['list-uuid-1', 'list-uuid-2'], 'properties' => ['COMPANY' => 'Acme'], ]); echo $contact['id']; ``` ### List contacts Retrieve a paginated list of contacts. ```php theme={null} $contacts = $client->contacts()->list(); // With pagination $contacts = $client->contacts()->list(['page' => 2]); echo $contacts['meta']['total']; // total contacts ``` ### Get a contact ```php theme={null} $contact = $client->contacts()->get('contact-uuid'); echo $contact['email']; echo $contact['properties']['COMPANY']; ``` ### Update a contact ```php theme={null} $contact = $client->contacts()->update('contact-uuid', [ 'first_name' => 'Johnny', 'unsubscribed' => true, ]); ``` ### Delete a contact ```php theme={null} $client->contacts()->delete('contact-uuid'); ``` ### Add a contact to lists ```php theme={null} $contact = $client->contacts()->addToLists('contact-uuid', [ 'list-uuid-1', 'list-uuid-2', ]); ``` ### List a contact's lists ```php theme={null} $lists = $client->contacts()->listLists('contact-uuid'); // With pagination $lists = $client->contacts()->listLists('contact-uuid', ['page' => 2]); ``` ### Remove a contact from a list ```php theme={null} $client->contacts()->removeFromList('contact-uuid', 'list-uuid'); ``` ## Contact properties Contact properties let you define custom fields for your contacts. ### Create a property ```php theme={null} $property = $client->contactProperties()->create([ 'key' => 'company', 'type' => 'string', // "string", "number", or "date" 'fallback_value' => 'N/A', // optional ]); echo $property['id']; ``` ### List properties ```php theme={null} $properties = $client->contactProperties()->list(); // With pagination $properties = $client->contactProperties()->list(['page' => 2]); ``` ### Update a property ```php theme={null} $property = $client->contactProperties()->update('property-uuid', [ 'key' => 'organization', 'fallback_value' => 'Unknown', ]); ``` ### Delete a property ```php theme={null} $client->contactProperties()->delete('property-uuid'); ``` A `SendKitException` with status `409` is thrown if the property is used in segment filters. # Python Source: https://docs.sendkit.dev/sdks/python Send emails from Python using the SendKit SDK. View on GitHub View on PyPI ## Install ```bash theme={null} pip install sendkit ``` ## Send email ```python theme={null} from sendkit import SendKit client = SendKit("sk_your_api_key") result = client.emails.send( from_="Your Name ", to="recipient@example.com", subject="Hello from SendKit", html="

Welcome!

Your first email with SendKit.

", ) print(result["id"]) ``` # Ruby Source: https://docs.sendkit.dev/sdks/ruby Send emails from Ruby using the SendKit SDK. View on GitHub View on RubyGems ## Install ```bash gem theme={null} gem install sendkit ``` ```ruby Gemfile theme={null} gem "sendkit" ``` ## Send email ```ruby theme={null} require "sendkit" client = SendKit::Client.new("sk_your_api_key") result = client.emails.send( from: "Your Name ", to: "recipient@example.com", subject: "Hello from SendKit", html: "

Welcome!

Your first email with SendKit.

" ) puts result["id"] ``` # Rust Source: https://docs.sendkit.dev/sdks/rust Send emails from Rust using the SendKit SDK. View on GitHub View on crates.io ## Install Add to your `Cargo.toml`: ```toml theme={null} [dependencies] sendkit = "1" tokio = { version = "1", features = ["rt-multi-thread", "macros"] } ``` ## Send email ```rust theme={null} use sendkit::{SendKit, SendEmailParams}; #[tokio::main] async fn main() { let client = SendKit::new("sk_your_api_key").unwrap(); let response = client.emails.send(&client, &SendEmailParams { from: "Your Name ".into(), to: vec!["recipient@example.com".into()], subject: "Hello from SendKit".into(), html: Some("

Welcome!

Your first email with SendKit.

".into()), ..Default::default() }).await.unwrap(); println!("Email sent: {}", response.id); } ``` # Event Types Source: https://docs.sendkit.dev/webhooks/event-types All webhook event types supported by SendKit SendKit sends webhook events for both email and contact activity. Each event includes a JSON payload with event-specific data. ## Email events | Event | Description | | -------------------------------- | ---------------------------------------------------------- | | `email.sent` | Email was accepted and sent to the recipient's mail server | | `email.delivered` | Email was successfully delivered to the recipient's inbox | | `email.opened` | Recipient opened the email | | `email.clicked` | Recipient clicked a link in the email | | `email.bounced` | Email permanently rejected by the recipient's mail server | | `email.complained` | Recipient marked the email as spam | | `email.rejected` | Email was rejected before sending | | `email.failed` | Email failed to send | | `email.delivery_delayed` | Email delivery was temporarily delayed | ## Contact events | Event | Description | | ------------------------- | -------------------------------- | | `contact.created` | A new contact was created | | `contact.updated` | A contact's details were updated | | `contact.deleted` | A contact was deleted | # contact.created Source: https://docs.sendkit.dev/webhooks/events/contact-created Triggered when a new contact is created ## When it triggers This event fires when a new contact is added to your account, either through the API, the dashboard, or automatically when sending an email to a new address. ## Payload ```json theme={null} { "type": "contact.created", "data": { "contact_id": "ct_abc123", "email": "user@example.com", "first_name": "John", "last_name": "Doe", "created_at": "2026-03-02T12:00:00+00:00" }, "created_at": "2026-03-02T12:00:00+00:00" } ``` ## Payload fields Unique identifier of the contact. Contact's email address. Contact's first name. Contact's last name. ISO 8601 timestamp of when the contact was created. # contact.deleted Source: https://docs.sendkit.dev/webhooks/events/contact-deleted Triggered when a contact is deleted ## When it triggers This event fires when a contact is permanently deleted from your account. ## Payload ```json theme={null} { "type": "contact.deleted", "data": { "contact_id": "ct_abc123", "email": "user@example.com" }, "created_at": "2026-03-02T13:00:00+00:00" } ``` ## Payload fields Unique identifier of the contact. Contact's email address. # contact.updated Source: https://docs.sendkit.dev/webhooks/events/contact-updated Triggered when a contact's details are updated ## When it triggers This event fires when any of the following contact fields are changed: `email`, `first_name`, `last_name`, or `unsubscribed`. Changes to other fields do not trigger this event. ## Payload ```json theme={null} { "type": "contact.updated", "data": { "contact_id": "ct_abc123", "email": "user@example.com", "first_name": "John", "last_name": "Doe", "unsubscribed": false, "updated_at": "2026-03-02T12:30:00+00:00" }, "created_at": "2026-03-02T12:30:00+00:00" } ``` ## Payload fields Unique identifier of the contact. Contact's email address. Contact's first name. Contact's last name. Whether the contact has unsubscribed from emails. ISO 8601 timestamp of when the contact was updated. # email.bounced Source: https://docs.sendkit.dev/webhooks/events/email-bounced Triggered when the email is permanently rejected by the recipient's mail server ## When it triggers This event fires when the recipient's mail server permanently rejects the email. Common causes include invalid email addresses, full mailboxes, or domain-level blocks. Bounced addresses are automatically added to the suppression list to protect your sender reputation. Future emails to this address will be blocked. ## Payload ```json theme={null} { "type": "email.bounced", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "tags": [], "created_at": "2026-03-02T12:00:02+00:00" }, "created_at": "2026-03-02T12:00:02+00:00" } ``` ## Payload fields Unique identifier of the email. Sender email address. Recipient email address. Email subject line. Tags associated with the email. Each tag has `name` and `value` string fields. Returns an empty array if no tags were set. ISO 8601 timestamp of when the email was created. # email.clicked Source: https://docs.sendkit.dev/webhooks/events/email-clicked Triggered when the recipient clicks a link in the email ## When it triggers This event fires when the recipient clicks a link in the email. Click tracking works by rewriting links through a tracking redirect. ## Payload ```json theme={null} { "type": "email.clicked", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "tags": [], "created_at": "2026-03-02T12:06:00+00:00" }, "created_at": "2026-03-02T12:06:00+00:00" } ``` ## Payload fields Unique identifier of the email. Sender email address. Recipient email address. Email subject line. Tags associated with the email. Each tag has `name` and `value` string fields. Returns an empty array if no tags were set. ISO 8601 timestamp of when the email was created. # email.complained Source: https://docs.sendkit.dev/webhooks/events/email-complained Triggered when the recipient marks the email as spam ## When it triggers This event fires when the recipient reports the email as spam through their email client. This generates a complaint feedback loop report. Complaint rates are closely monitored by email providers. High complaint rates can lead to domain-wide deliverability issues. The recipient is automatically added to the suppression list. ## Payload ```json theme={null} { "type": "email.complained", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "tags": [], "created_at": "2026-03-02T12:10:00+00:00" }, "created_at": "2026-03-02T12:10:00+00:00" } ``` ## Payload fields Unique identifier of the email. Sender email address. Recipient email address. Email subject line. Tags associated with the email. Each tag has `name` and `value` string fields. Returns an empty array if no tags were set. ISO 8601 timestamp of when the email was created. # email.delivered Source: https://docs.sendkit.dev/webhooks/events/email-delivered Triggered when the email is confirmed delivered to the recipient's inbox ## When it triggers This event fires when the recipient's mail server confirms that the email was accepted and delivered to the inbox. ## Payload ```json theme={null} { "type": "email.delivered", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "tags": [], "created_at": "2026-03-02T12:00:01+00:00" }, "created_at": "2026-03-02T12:00:01+00:00" } ``` ## Payload fields Unique identifier of the email. Sender email address. Recipient email address. Email subject line. Tags associated with the email. Each tag has `name` and `value` string fields. Returns an empty array if no tags were set. ISO 8601 timestamp of when the email was created. # email.delivery_delayed Source: https://docs.sendkit.dev/webhooks/events/email-delivery-delayed Triggered when email delivery is temporarily delayed ## When it triggers This event fires when the recipient's mail server temporarily defers delivery. SendKit will continue to retry delivery automatically. If delivery eventually succeeds, you will receive an `email.delivered` event. ## Payload ```json theme={null} { "type": "email.delivery_delayed", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "tags": [], "created_at": "2026-03-02T12:00:04+00:00" }, "created_at": "2026-03-02T12:00:04+00:00" } ``` ## Payload fields Unique identifier of the email. Sender email address. Recipient email address. Email subject line. Tags associated with the email. Each tag has `name` and `value` string fields. Returns an empty array if no tags were set. ISO 8601 timestamp of when the email was created. # email.failed Source: https://docs.sendkit.dev/webhooks/events/email-failed Triggered when the email fails to send ## When it triggers This event fires when SendKit is unable to send the email. This can happen due to internal errors, invalid configurations, or issues with the sending infrastructure. ## Payload ```json theme={null} { "type": "email.failed", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "tags": [], "created_at": "2026-03-02T12:00:03+00:00" }, "created_at": "2026-03-02T12:00:03+00:00" } ``` ## Payload fields Unique identifier of the email. Sender email address. Recipient email address. Email subject line. Tags associated with the email. Each tag has `name` and `value` string fields. Returns an empty array if no tags were set. ISO 8601 timestamp of when the email was created. # email.opened Source: https://docs.sendkit.dev/webhooks/events/email-opened Triggered when the recipient opens the email ## When it triggers This event fires when the recipient opens the email. Open tracking works by embedding a tracking pixel in the email HTML. Open tracking is not 100% accurate. Some email clients block tracking pixels or pre-load images, which can affect results. ## Payload ```json theme={null} { "type": "email.opened", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "tags": [], "created_at": "2026-03-02T12:05:00+00:00" }, "created_at": "2026-03-02T12:05:00+00:00" } ``` ## Payload fields Unique identifier of the email. Sender email address. Recipient email address. Email subject line. Tags associated with the email. Each tag has `name` and `value` string fields. Returns an empty array if no tags were set. ISO 8601 timestamp of when the email was created. # email.rejected Source: https://docs.sendkit.dev/webhooks/events/email-rejected Triggered when an email is rejected before sending ## When it triggers This event fires when an email is rejected before it is sent. Common causes include invalid email syntax, disposable email addresses, or addresses on the suppression list. ## Payload ```json theme={null} { "type": "email.rejected", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "tags": [], "created_at": "2026-03-02T12:00:00+00:00" }, "created_at": "2026-03-02T12:00:00+00:00" } ``` ## Payload fields Unique identifier of the email. Sender email address. Recipient email address. Email subject line. Tags associated with the email. Each tag has `name` and `value` string fields. Returns an empty array if no tags were set. ISO 8601 timestamp of when the email was created. # email.sent Source: https://docs.sendkit.dev/webhooks/events/email-sent Triggered when an email is accepted and sent to the recipient's mail server ## When it triggers This event fires when SendKit successfully hands off the email to the recipient's mail server. This does not guarantee inbox delivery — see `email.delivered` for confirmation. ## Payload ```json theme={null} { "type": "email.sent", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "tags": [], "created_at": "2026-03-02T12:00:00+00:00" }, "created_at": "2026-03-02T12:00:00+00:00" } ``` ## Payload fields Unique identifier of the email. Sender email address. Recipient email address. Email subject line. Tags associated with the email. Each tag has `name` and `value` string fields. Returns an empty array if no tags were set. ISO 8601 timestamp of when the email was created. # Introduction Source: https://docs.sendkit.dev/webhooks/introduction Receive real-time notifications about email and contact events via webhooks Webhooks allow your application to receive real-time HTTP notifications when events occur in SendKit. Instead of polling the API, SendKit pushes event data to your endpoint as it happens. ## How it works Provide an HTTPS URL where SendKit will send event notifications. Subscribe to specific events (e.g. `email.delivered`) or use the wildcard `*` to receive all events. SendKit sends a `POST` request with a JSON payload and an HMAC-SHA256 signature for verification. ## Payload format Every webhook delivery is a `POST` request with a JSON body: ```json theme={null} { "type": "email.delivered", "data": { "email_id": "em_abc123", "from": "hello@yourdomain.com", "to": "user@example.com", "subject": "Welcome to SendKit", "created_at": "2026-03-02T12:00:00+00:00" }, "created_at": "2026-03-02T12:00:00+00:00" } ``` ## Available events SendKit supports two categories of events: | Category | Events | | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Email** | `email.sent`, `email.delivered`, `email.bounced`, `email.complained`, `email.opened`, `email.clicked`, `email.rejected`, `email.failed`, `email.delivery_delayed` | | **Contact** | `contact.created`, `contact.updated`, `contact.deleted` | See the full list of events with payload examples. # Retries and failures Source: https://docs.sendkit.dev/webhooks/retries How SendKit handles failed webhook deliveries ## Retry behavior When a webhook delivery fails, SendKit automatically retries the request: SendKit makes up to **3 total attempts** (1 initial + 2 retries) with a 60-second delay between each: | Attempt | Delay | | ----------------- | ---------------------------------- | | Initial request | Immediate | | 1st retry | 60 seconds after initial failure | | 2nd retry (final) | 60 seconds after 1st retry failure | A delivery is considered failed when: * Your endpoint returns a non-2xx status code * The request times out (10 second limit) * The connection cannot be established ## Automatic pausing If a webhook accumulates **5 consecutive failures**, SendKit automatically pauses it to prevent unnecessary load on your server. A failure is counted once all 3 attempts for a single delivery are exhausted — individual retry attempts do not count separately. When this happens: * The webhook status changes to **Paused** * The team owner receives an email notification * No further deliveries are attempted until you re-enable the webhook To resume deliveries, go to the webhook settings in your dashboard and change the status back to **Enabled**. This resets the failure counter. ## Best practices Always return a `200` status code as quickly as possible. Process webhook data asynchronously in a background job. * **Respond within 10 seconds** — Requests that take longer will time out and count as a failure. * **Use HTTPS** — Webhook endpoints must use HTTPS. * **Handle duplicates** — Webhooks may be retried, so make your processing idempotent. * **Replay events** — Use the replay feature in the dashboard to re-send any past webhook delivery. ## Monitoring Every webhook delivery is logged with: * The full request payload * Response status code and body * Delivery timestamp or failure timestamp * Number of attempts You can view these logs in real time from the webhook detail page in your dashboard. # Verifying signatures Source: https://docs.sendkit.dev/webhooks/signatures Verify webhook authenticity using HMAC-SHA256 signatures Every webhook request includes an `X-Webhook-Signature` header containing an HMAC-SHA256 signature. You should always verify this signature before processing the payload to ensure the request came from SendKit. ## How it works SendKit signs the JSON payload using your webhook's signing secret: ``` HMAC-SHA256(JSON payload, signing_secret) ``` The resulting hex digest is sent in the `X-Webhook-Signature` header. ## Verification examples ```js Node.js theme={null} import crypto from 'crypto'; import express from 'express'; const app = express(); // Important: use raw body for signature verification app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf.toString(); } })); const verify = (rawBody, signature, secret) => { const expected = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) ); }; app.post('/webhooks/sendkit', (req, res) => { const signature = req.headers['x-webhook-signature']; const secret = process.env.SENDKIT_WEBHOOK_SECRET; if (!verify(req.rawBody, signature, secret)) { return res.status(401).send('Invalid signature'); } // Process the event console.log(req.body.type); res.status(200).send('OK'); }); ``` ```php PHP theme={null} $payload = file_get_contents('php://input'); $signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE']; $secret = env('SENDKIT_WEBHOOK_SECRET'); $expected = hash_hmac('sha256', $payload, $secret); if (!hash_equals($expected, $signature)) { http_response_code(401); exit('Invalid signature'); } $event = json_decode($payload, true); // Process the event ``` ```python Python theme={null} import hmac import hashlib from flask import Flask, request app = Flask(__name__) def verify(raw_body: bytes, signature: str, secret: str) -> bool: expected = hmac.new( secret.encode(), raw_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature) @app.route('/webhooks/sendkit', methods=['POST']) def webhook(): signature = request.headers.get('X-Webhook-Signature') secret = 'your_signing_secret' # Important: use raw body, not parsed JSON if not verify(request.get_data(), signature, secret): return 'Invalid signature', 401 event = request.get_json() # Process the event return 'OK', 200 ``` ```go Go theme={null} package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "io" "net/http" ) func verify(rawBody []byte, signature, secret string) bool { mac := hmac.New(sha256.New, []byte(secret)) mac.Write(rawBody) expected := hex.EncodeToString(mac.Sum(nil)) return hmac.Equal([]byte(expected), []byte(signature)) } func webhookHandler(w http.ResponseWriter, r *http.Request) { // Important: use raw body, not re-serialized JSON rawBody, _ := io.ReadAll(r.Body) signature := r.Header.Get("X-Webhook-Signature") secret := "your_signing_secret" if !verify(rawBody, signature, secret) { http.Error(w, "Invalid signature", http.StatusUnauthorized) return } // Process the event using rawBody w.WriteHeader(http.StatusOK) } ``` ## Rotating secrets You can rotate your webhook's signing secret at any time from the dashboard. After rotation, use the new secret to verify future deliveries. Previous deliveries will still show the old signature in logs. After rotating a secret, update your application immediately. Requests signed with the old secret will fail verification.