<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Ketevan Bostoganashvili]]></title><description><![CDATA[Ketevan Bostoganashvili]]></description><link>https://ketevanbostoganashvili.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 20 Jun 2026 12:31:24 GMT</lastBuildDate><atom:link href="https://ketevanbostoganashvili.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Send emails with Vercel and Mailtrap]]></title><description><![CDATA[This article is based on Mailtrap's official tutorial on how to send email in Vercel.
Before we start
Required accounts

Vercel account - to host your applications and manage environment variables

Mailtrap account - to send emails with high delivera...]]></description><link>https://ketevanbostoganashvili.hashnode.dev/send-emails-with-vercel-and-mailtrap</link><guid isPermaLink="true">https://ketevanbostoganashvili.hashnode.dev/send-emails-with-vercel-and-mailtrap</guid><category><![CDATA[mailtrap]]></category><category><![CDATA[Vercel]]></category><category><![CDATA[email]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Ketevan Bostoganashvili]]></dc:creator><pubDate>Tue, 02 Sep 2025 12:48:30 GMT</pubDate><content:encoded><![CDATA[<p>This article is based on Mailtrap's official tutorial on <a target="_blank" href="https://help.mailtrap.io/article/186-send-email-in-vercel">how to send email in Vercel</a>.</p>
<h2 id="heading-before-we-start">Before we start</h2>
<h3 id="heading-required-accounts">Required accounts</h3>
<ul>
<li><p>Vercel account - to host your applications and manage environment variables</p>
</li>
<li><p>Mailtrap account - to send emails with high deliverability rates</p>
</li>
<li><p>Next.js project - to implement the email functionality</p>
</li>
</ul>
<h3 id="heading-prerequisites-setup">Prerequisites setup</h3>
<ol>
<li><p>Verify your email sending domain - Mailtrap allows you to send emails only from a verified domain. Follow <a target="_blank" href="https://help.mailtrap.io/article/69-sending-domain-setup">this guide</a> to set up domain verification.</p>
</li>
<li><p>Get your API token - Ensure your <a target="_blank" href="https://mailtrap.io/api-tokens">API Token</a> has admin access level to your domain and email sending capabilities.</p>
</li>
</ol>
<h2 id="heading-step-1-set-up-mailtrap">Step 1: Set up Mailtrap</h2>
<p>Navigate to your Mailtrap dashboard and locate your API credentials:</p>
<ol>
<li><p>Click on Settings → API Tokens</p>
</li>
<li><p>Review all active tokens, their creators, and access levels</p>
</li>
<li><p>If you don't have an API key, click Add Token</p>
</li>
<li><p>Assign the desired permissions (check API/SMTP permissions)</p>
</li>
<li><p>Click Save and store your API key securely</p>
</li>
</ol>
<p>Note that you won't be able to see the API key again after creation. For more detailed information, refer to the <a target="_blank" href="https://help.mailtrap.io/article/103-api-tokens">Mailtrap API Tokens guide</a>.</p>
<h2 id="heading-step-2-create-a-nextjs-function">Step 2: Create a Next.js function</h2>
<p>Create a new API route in your Next.js application to handle email sending via Mailtrap:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// app/api/send/route.ts</span>
<span class="hljs-keyword">const</span> MAILTRAP_API_TOKEN = process.env.MAILTRAP_API_TOKEN;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">POST</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://send.api.mailtrap.io/api/send"</span>, {
    method: <span class="hljs-string">"POST"</span>,
    headers: {
      <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${MAILTRAP_API_TOKEN}</span>`</span>,
      <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>
    },
    body: <span class="hljs-built_in">JSON</span>.stringify({
      <span class="hljs-keyword">from</span>: { email: <span class="hljs-string">"no-reply@yourdomain.com"</span> },
      to: [{ email: <span class="hljs-string">"support@yourdomain.com"</span> }],
      subject: <span class="hljs-string">"Hello from Vercel + Mailtrap"</span>,
      text: <span class="hljs-string">"This is a test email sent via Mailtrap API."</span>
    })
  });

  <span class="hljs-keyword">if</span> (res.ok) {
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();
    <span class="hljs-keyword">return</span> Response.json(data);
  }

  <span class="hljs-keyword">return</span> Response.json(
    { error: <span class="hljs-string">'Failed to send email'</span> }, 
    { status: <span class="hljs-number">500</span> }
  );
}
</code></pre>
<h2 id="heading-step-3-deploy-on-vercel">Step 3: Deploy on Vercel</h2>
<h3 id="heading-add-your-mailtrap-api-key-to-vercel">Add your Mailtrap API key to Vercel</h3>
<p>Configure your environment variables in the Vercel dashboard:</p>
<ol>
<li><p>Open your Vercel dashboard</p>
</li>
<li><p>Navigate to the Settings for your target project</p>
</li>
<li><p>Find the Environment Variables section</p>
</li>
<li><p>Add a new variable:</p>
<ul>
<li><p>Key: MAILTRAP_API_TOKEN</p>
</li>
<li><p>Value: Your actual Mailtrap API token</p>
</li>
</ul>
</li>
<li><p>Click Save</p>
</li>
</ol>
<p><strong>Important</strong>: Vercel environment variables only become available after redeployment. Make sure to either push a new commit or click Deploy again in the Vercel dashboard.</p>
<h3 id="heading-deploy-your-application">Deploy your application</h3>
<p>Deploy your application to Vercel using one of these methods:</p>
<ol>
<li><p>Git integration (recommended):</p>
<ul>
<li><p>Connect your repository to Vercel</p>
</li>
<li><p>Push your changes to trigger automatic deployment</p>
</li>
</ul>
</li>
<li><p>Vercel CLI:</p>
</li>
</ol>
<pre><code class="lang-powershell">npm i <span class="hljs-literal">-g</span> vercel
vercel -<span class="hljs-literal">-prod</span>
</code></pre>
<ol start="3">
<li><p>Vercel dashboard:</p>
<ul>
<li><p>Import your project from Git</p>
</li>
<li><p>Configure build settings</p>
</li>
<li><p>Deploy manually</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-test-your-mailtrap-vercel-integration">Test your Mailtrap Vercel integration</h2>
<h3 id="heading-test-the-api-endpoint">Test the API endpoint</h3>
<p>After deployment, test your email functionality:</p>
<ol>
<li>Test the basic endpoint:</li>
</ol>
<pre><code class="lang-powershell"><span class="hljs-built_in">curl</span> <span class="hljs-literal">-X</span> POST https://your<span class="hljs-literal">-project</span>.vercel.app/api/send
</code></pre>
<ol start="2">
<li>Test the contact form endpoint:</li>
</ol>
<pre><code class="lang-powershell"><span class="hljs-built_in">curl</span> <span class="hljs-literal">-X</span> POST https://your<span class="hljs-literal">-project</span>.vercel.app/api/contact \
  <span class="hljs-literal">-H</span> <span class="hljs-string">"Content-Type: application/json"</span> \
  <span class="hljs-literal">-d</span> <span class="hljs-string">'{
    "name": "John Doe",
    "email": "john@example.com", 
    "message": "Test message"
  }'</span>
</code></pre>
<h3 id="heading-verify-email-delivery">Verify email delivery</h3>
<p>After testing, confirm successful integration:</p>
<ol>
<li><p>Check your inbox for notification emails</p>
</li>
<li><p>Review delivery status in <a target="_blank" href="https://help.mailtrap.io/article/71-email-logs">Mailtrap Email Logs</a></p>
</li>
<li><p>Monitor email analytics and delivery metrics</p>
</li>
</ol>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>That's it for integrating Vercel with Mailtrap! You now have a simple three-step process: set up your Mailtrap account with API credentials, create a Next.js API route to send emails, and deploy to Vercel with your environment variables configured. This setup gives you reliable email sending from your serverless applications without complex infrastructure management.</p>
<p>If you’d like to learn more about the topic, read our dedicated blog post on <a target="_blank" href="https://mailtrap.io/blog/vercel-send-email/">Vercel SMTP integration</a>.</p>
]]></content:encoded></item><item><title><![CDATA[How to Test Emails in Salesforce with Mailtrap Email Testing]]></title><description><![CDATA[While Salesforce’s testing capabilities are sufficient for running small deliverability tests or previewing your emails, they may not be enough for inspecting and debugging emails in detail. Plus, some methods may bear the risk of spamming contacts w...]]></description><link>https://ketevanbostoganashvili.hashnode.dev/how-to-test-emails-in-salesforce-with-mailtrap-email-testing</link><guid isPermaLink="true">https://ketevanbostoganashvili.hashnode.dev/how-to-test-emails-in-salesforce-with-mailtrap-email-testing</guid><dc:creator><![CDATA[Ketevan Bostoganashvili]]></dc:creator><pubDate>Wed, 11 Sep 2024 07:46:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726040680697/114746d4-1378-48e3-a787-7324f60be444.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While Salesforce’s testing capabilities are sufficient for running small deliverability tests or previewing your emails, they may not be enough for inspecting and debugging emails in detail. Plus, some methods may bear the risk of spamming contacts with test emails. </p>
<p>That’s where Mailtrap Email Testing comes into play. And today, we’ll teach you how to execute various tests in Salesforce using Mailtrap. </p>
<h2 id="heading-what-is-mailtrap-email-testing"><strong>What is Mailtrap Email Testing?</strong></h2>
<p><a target="_blank" href="https://mailtrap.io/email-sandbox/">Mailtrap Email Testing</a> is an Email Sandbox – a safe environment to inspect and debug emails in staging and development environments. It captures all the SMTP traffic and traps your test emails in a virtual inbox. Email Testing is part of the <a target="_blank" href="https://mailtrap.io/">Mailtrap Email Delivery Platform</a>. </p>
<p>Some of the features of Email Testing include </p>
<ul>
<li><p>A <a target="_blank" href="https://mailtrap.io/fake-smtp-server/">fake SMTP server</a> to eliminate the risk of spamming users; </p>
</li>
<li><p>HTML analysis to check how your emails will render in different email clients; </p>
</li>
<li><p>Spam analysis for popular spam filters and blacklists; </p>
</li>
<li><p>SMTP and API for easy integration; </p>
</li>
<li><p>Ready-made code snippets for popular languages and frameworks; </p>
</li>
<li><p>Multiple inboxes for different projects and stages.</p>
</li>
</ul>
<p><a target="_blank" href="https://mailtrap.io/register/signup?ref=header"><strong>Try Email Testing for Free</strong></a> </p>
<h2 id="heading-when-should-you-use-mailtrap-email-testing"><strong>When should you use Mailtrap Email Testing?</strong></h2>
<p>There are several use cases where you should opt for Mailtrap Email Testing. Let’s quickly discuss each of them below. </p>
<h3 id="heading-avoiding-spamming-users-with-test-emails"><strong>Avoiding spamming users with test emails</strong></h3>
<p>You can easily avoid annoying your recipients by using Mailtrap Email Testing. It will create sort of a barrier between Salesforce and your contacts. As a result, all your test emails will end up in a virtual inbox. </p>
<p><img src="https://lh3.googleusercontent.com/SZIS9_JHAtkdLUhqrmqD2PXIUlgugzhD188l9pETU9UKUem_Uhn4BjaWiogVxQGHyM9Bz0Kk1n15X-5zFrNBx4tOZptp_yvGN8QdNgCEr1S1RcwoZ_y1_7iJBzKWTFpthwqAHxOu1IO5r4nDs-GU2FE" alt /></p>
<h3 id="heading-testing-email-format-and-content"><strong>Testing email format and content</strong></h3>
<p>With Email Testing, you can easily check HTML/CSS in your templates for different email clients. You’ll see a detailed chart with problematic lines of code marked in red. Each problematic element has a description of the support level for each client. </p>
<p><img src="https://lh5.googleusercontent.com/fJCv9cKbS-w1g5iZKFDIldUXiQ4dhhrdr-PW-LjxcuDWvUmeQ32mqKot5fHKWcw4qaPcmJNHmz-w9l37fHijob7XkbRWoYBIAGs9WVL6G5dZsK_gvvdkUuQrfetBbUu17EZuZTueMyH0P2CCJaeOXCs" alt /></p>
<p>On top of that, Email Testing has a Spam Analysis feature. </p>
<p>The feature is particularly important for your deliverability and sender reputation. Why? The score gives you a clear indication if mailbox providers may automatically label your email template as spam. Plus, you get to see if your domain or IP appear in any of the blacklists.  </p>
<p>That way, you’ll get the chance to make the emails less spammy in staging and protect your <a target="_blank" href="https://mailtrap.io/blog/email-sender-reputation/">sender reputation</a> in production. </p>
<p><img src="https://lh4.googleusercontent.com/JzIdrBc70qV_lBXxRx0hhz3QNaxifxLF-UomZtp6vCVkhcKt2xTT2YsZ6-V4jQ5eR8V2kTKXLVTZgPLim3MGtiYh7UMoBv9rYMHpy5rfK3nuHzLSyIfpv49-n9PMHN5NXSawCREFLGsIWmF779K_beE" alt /></p>
<p>Additionally, you can test your pre-made templates with Mailtrap API with which you can easily switch from staging to production once you’re ready to start sending.</p>
<p>All you have to do is enable sandbox, specify the inbox ID to receive template test, and then send it through the API in the production environment.</p>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/04/templates-6.png" alt /></p>
<p><a target="_blank" href="https://mailtrap.io/register/signup?ref=header"><strong>Try Email Testing for Free</strong></a> </p>
<h3 id="heading-keeping-all-test-emails-in-one-place"><strong>Keeping all test emails in one place</strong></h3>
<p>Email Testing captures all your outgoing <a target="_blank" href="https://mailtrap.io/blog/salesforce-mass-email/">Salesforce emails</a> and keeps them organized in different inboxes for various projects and testing stages. </p>
<p>So, Email Testing and Salesforce create a robust combo for in-depth testing and debugging. </p>
<h2 id="heading-how-to-test-email-deliverability"><strong>How to test email deliverability</strong></h2>
<p>For the instructions below, we’ll assume that you already have a Salesforce account up and running. </p>
<p>But to start testing, you’ll also need to set up a Mailtrap account (if you have it already, you can skip this step). </p>
<ol>
<li>Go to <a target="_blank" href="https://mailtrap.io/register/signup?ref=header">Mailtrap’s sign up page</a> and choose the desired method of registration; </li>
</ol>
<p><img src="https://lh4.googleusercontent.com/sY1yifc-rOaZdPqD89xHGkshMPyMzkLZ8T05lj4f6Qi97TfSFXcymEgVLKg-uXGKm5O8igwaeL8Eka3bVEzCad7U-0D9gIVT7buGtAv8bqnRxwCLTjQDABJX2Uji4Fm7HUE1oFb_Zjzeuj0AsPmhmK4" alt /></p>
<ol start="2">
<li>Go to <em>Email Testing → Inboxes</em> to find your first inbox created by default. It’s called ‘My Inbox’ but you can easily rename it by clicking the pencil icon on the right. It’s also possible to create additional projects and inboxes if needed. </li>
</ol>
<p><img src="https://lh5.googleusercontent.com/rJMS782FTYHpKp2oGt1gtyIQOHWpOR1KC0O7ETCy_fp7xnapIIZYuQckPEang0zRR11FoUu0Hk4FZ1ZrJw2ssKAM5UhcvHdsOCCB7a4dxz0NbezINwW47hY2JaNBlpMBNSSnVBiIahHz-cWB25aqy30" alt /></p>
<ol start="3">
<li>Click on your inbox and hit <em>Show Credentials</em> to reveal the credentials for the fake SMTP server. </li>
</ol>
<p><img src="https://lh5.googleusercontent.com/5dV6UVwbbd8kUCXNXVkap76AogDzqfAyf_hHkU-cLFomXrNvaD9fFNvSAYAcW-3i3Bm4jWR2e3KeSR-GQPQkC0qBTEe733N1roT1y57aWqYKsxHz01ipTQ4RLcSthMpwDJW7RFVWLStyLKAf_X8JdEo" alt /></p>
<ol start="4">
<li>Go to your Salesforce account and navigate to <em>Setup</em>  <em>→ Email (under Administration)  → Email Relays.</em></li>
</ol>
<p><img src="https://lh6.googleusercontent.com/eUV8IxoJIKOwkR4f_a7nUMPlpJL9b3IJrQ6mBDZwhyW8QaVFsEvHbTjBWcM6jn6C2gSDtEDxuebcEy61ZeIIRD3-6eU2MRrFHW2N-KysSOMZi-GxxyEDWAHmPKtX0Vbadg49JuwSH8h8kQljt-CQa8o" alt /></p>
<ol start="5">
<li>Click <em>Create Email Relay</em> and fill out the form with Email Testing’s SMTP credentials as in the example below: </li>
</ol>
<p><img src="https://lh3.googleusercontent.com/PCLYuKqmIjA2uVzXQOQa3GLUBe57evMC2t4h-vAlGSv5pM6LlJHCt4Mvx1FpxE_2zqLZwp_0D30Hc6mcnf6UqBVp_RWfTY03rwke56hvebrUNDLV7Rnq8vtijxYZxOZKJxaEAWUEi04j1a4r7uJiPTA" alt /></p>
<ol start="6">
<li>Click <em>Enable SMTP Auth</em> to connect to the SMTP server with authentication. Enter your SMTP username and password. </li>
</ol>
<p><img src="https://lh3.googleusercontent.com/H_KcfQXDQMnNNu88URSFxFzH2NYpLY3i7uAhGDyj4k-MOAElYBV2gN5eCWIao2_PJBErV4GkVnqDMs1NPiICJEdmqm1sPM3Uh0tS7njcHu6pYSQiLKipFywMfDwl4cSZ_flpPIetMxsfD-5Dd6zM0ec" alt /></p>
<ol start="7">
<li>Click <em>Save.</em> Head to <em>Email Domain Filters</em> and click <em>Create Email Domain Filter.</em> This step is necessary to activate the relay. </li>
</ol>
<p><img src="https://lh3.googleusercontent.com/EvaFlrgdAGLMwEwlaYxOqdLoTHAVoqtPihDZj8p2sP9vJGQIDNODJt_ksppdlpEYX1rlGtXLIuFPK---HcFFMFjs9C1FqCZ2yl3J_7NvP-y7KuIv_fIyruGeXabovnLholxvO80QyW4lBPn8sGEfDtU" alt /></p>
<ol start="8">
<li>There, enter ‘*’ as the default wildcard for <em>Sender Domain</em> and <em>Recipient Domain.</em> Then mark the <em>Active</em> checkbox, otherwise the relay won’t be applied. Click <em>Save.</em> </li>
</ol>
<p><img src="https://lh5.googleusercontent.com/dNrZ0kOjut1ebjUdg8J7ihtDy6zO4PMSxeHTnTZdmLqKunjEz0hz29NkN5vz1k6fyOMoznkS-OGrsFpJYrkJlUlv6uFArNS7UeVLu6_oPKSvsg6NNTUeP4t0pFksFQl71iQ3b2OtedNzvr2yUOrZZXU" alt /></p>
<p>Now it’s time to send test emails with Apex and see if they will be delivered to the Email Testing’s virtual inbox. For more details on <a target="_blank" href="https://mailtrap.io/blog/apex-send-email/">sending emails with Apex</a>, check out this blog post. </p>
<p>In your Salesforce account, navigate to <em>Setup</em> and type <em>Apex Classes</em> in a quick find box. </p>
<p><img src="https://lh4.googleusercontent.com/Re6aiaH4h9Ddix8tORXSjeMnYfirD9-iUWGxE8sJCqWAJ0PN99zMHiVIWLEoqaawtkiSxnM0_-ChQx4kLq-a0GhMbotouzqb36NGjoQn3B-SWTJsdGxIr0JsU0YK0TiVr6zUtr7fEjA23nKvw1HarPE" alt /></p>
<p>Click <em>New</em> to create a new Apex class that will send a simple email. Paste the following snippet and press <em>Save.</em> </p>
<p><em>Don’t forget to substitute recipient@example.com and no-reply@example.com with actual email addresses.</em> </p>
<pre><code class="lang-javascript">public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SendSingleEmail</span> </span>{
    public <span class="hljs-keyword">void</span> sendSingleEmailMethod(){

        Messaging.reserveSingleEmailCapacity(<span class="hljs-number">2</span>);
        Messaging.SingleEmailMessage mymail = <span class="hljs-keyword">new</span> Messaging.SingleEmailMessage();

        <span class="hljs-comment">// Ensure that addresses are correctly formatted and matching case</span>
        <span class="hljs-built_in">String</span>[] toAddresses = <span class="hljs-keyword">new</span> <span class="hljs-built_in">String</span>[] {<span class="hljs-string">'recipient@example.com'</span>};

        mymail.setToAddresses(toAddresses);
        mymail.setReplyTo(<span class="hljs-string">'no-reply@example.com'</span>);
        mymail.setSenderDisplayName(<span class="hljs-string">'Salesforce Support'</span>);
        mymail.setSubject(<span class="hljs-string">'Test Email '</span>);
        mymail.setPlainTextBody(<span class="hljs-string">'This is the first test email sent from Salesforce with Mailtrap Email Testing'</span>);
        mymail.setHtmlBody(<span class="hljs-string">'&lt;p&gt;This is the first test email sent from Salesforce with Mailtrap Email Testing&lt;/p&gt;'</span>);

        Messaging.sendEmail(<span class="hljs-keyword">new</span> Messaging.SingleEmailMessage[] { mymail });
    }
}
</code></pre>
<p><strong>Copy</strong></p>
<p>Go back to the Apex classes page, click <em>Developer Console,</em> and open the class we just created. Under debug, choose <em>Open Execute Anonymous Window.</em> </p>
<p><img src="https://lh5.googleusercontent.com/yeEtIVhdXdbrZ_K2B9RLEGsBPfuzdeWTNnl__Nrz43-sNd0BzcUe7hsDQQSg4emvbip-Veu1QdTFLNmIikZt4BRk3jPUXUFQ7LRmaQaJ8c3oRqYTQa0naah7mIkPPTcOTV0d1P1VlQEOLZibCSiqfq8" alt /></p>
<p>Type the following line of code and click <em>Execute.</em> </p>
<pre><code class="lang-javascript">sendSingleEmail obj = <span class="hljs-keyword">new</span> sendSingleEmail();
obj.sendSingleEmailMethod();
</code></pre>
<p><strong>Copy</strong></p>
<p>Under logs, a success message will appear. Head to your Mailtrap Email Testing inbox and you’ll see the test email there. This confirms that Salesforce deliverability doesn’t have any issues. </p>
<p><img src="https://lh4.googleusercontent.com/0T9pPsShYBQnbawwqUCEGz_xkHAYTv-XloI95xTfGejg3HFOfW2NmU68bYSkVNell6zcXSVwyKTswBz8u7GBKWNjwVKXvwUq513hMgGoBEs4j09JIvWSH_AT02omdLj-drM_pyGA1dlFiW59711tlwo" alt /></p>
<h2 id="heading-how-to-test-email-templates"><strong>How to test email templates</strong></h2>
<p>Testing email templates is quite easy in Salesforce. And since we already have email relay configured, we just need to take a couple of additional steps. To make our tests interesting and leverage the full capabilities of Email Testing, let’s send text and HTML templates separately. </p>
<h3 id="heading-testing-text-templates"><strong>Testing text templates</strong></h3>
<p>We’ll create a sample text template in Salesforce. </p>
<ol>
<li>Go to <em>Setup → Email → Classic Email Templates</em> and click <em>New Template.</em> </li>
</ol>
<p><img src="https://lh4.googleusercontent.com/0Me_CaSQWk00kSZHyMbb8BGBrceYR8wjTWCHmBGxQdX_5PvyWKix62kAC8gHaxdJcA3dhKKcX0n_X9JqTYHyPGfJmjWzAuyrTYzgEjr0J1KTQ53kOTFTADb5D9wKm-Q8gGO2CacG4Qjs4ZGz22GLS4c" alt /></p>
<ol start="2">
<li>Select <em>Text</em> as the template type and press <em>Next.</em> </li>
</ol>
<p><img src="https://lh5.googleusercontent.com/RXBGojM3bxT_pV1MmUTZYzdoluMi7_TbbNFVJb0Du8PglhYTj-kRIknLGOdxMKCixDmnnvvKY5a_OBT9bGsTLIwNrDgzOu5yTxxM9NOU8cZs8dZEbj9qqTVHlb6_tAWZJrc7Fw1wJXLz-MlhoNP8dZ0" alt /></p>
<ol start="3">
<li>Configure the desired merged fields. For this example, we chose <em>Contact Fields</em> as the field type and the <em>First Name</em> as the field. Then, choose the folder in which the template will be saved, mark the checkbox next to <em>Available For Use,</em> name the template, and enter the subject line and body text. Don’t forget to insert the auto-generated merge field. Save the template. </li>
</ol>
<p><img src="https://lh4.googleusercontent.com/3Bxw-gijSqrT7zpEBh6hiX4KM_qhpHR1GXS614gazjACHg9apO20ujJCwOOdyxo0qDlBMjd7le1E5YKzlFwXBac3hIEpJ7sx3vIh1RFp4hXfoj2x4v0ytKN374PQ5iswOA3CesZCKEGadeiKRlbf2tM" alt /></p>
<ol start="4">
<li>Click <em>Send Test and Verify Merge Fields</em>. </li>
</ol>
<p><img src="https://lh6.googleusercontent.com/aTn9ZGOv_ymexVUqcQUOM5CCmij1G6y9QWfCLtNVNMM858jSWe9rvP_wHwhbM63NUPTz4CWEuTM0EZgEVZAjQUIYauXSmVGJbnhN26nXwX8yGg26TaFoCYsdneTMEfHOnhUbY_F1m_y5no3zgHoF3B8" alt /></p>
<ol start="5">
<li>In the pop-up window, choose the contact you want to test the template for. Tick <em>Send email preview to</em> and enter your email address. </li>
</ol>
<p><img src="https://lh3.googleusercontent.com/6jI5Jio1qfcEGExC5YiSEmTQbwVDC0kN62grKs2KCHAA9o-a4twwj_WsRnUAZUG4OMRagFH731zk9_hKTwZjShgDtwquzldhEh69gtdMwjI3WwYJyED_QpC77cZ-M-vfsGbxSbV8XY6IclCneXUU2Hs" alt /></p>
<ol start="6">
<li>Click <em>OK.</em> Now check your Email Testing inbox. The test template will be right there. However, you won’t find it in your real inbox since we sent it through the fake SMTP server. </li>
</ol>
<p><img src="https://lh3.googleusercontent.com/DRhQQ-36x70LBCvLsZ5qB_i7cgNkiUXfJWmcOpjYTOeivo1jdtbuDUlk9AVN1keBouetczhHRtZ52jt7_IIHnwU62j8X0i0Tuz-lSXnTjoluERX5CjFP5qF_0KeUuJNb2U3gk63cLuYlBk1GWe-JXhU" alt /></p>
<h3 id="heading-testing-html-templates"><strong>Testing HTML templates</strong></h3>
<p>Just like in the previous example, we should start by creating a template, but instead of text, let’s select <em>Custom (without using Classic Letterhead).</em> Click <em>Next.</em> </p>
<p><img src="https://lh4.googleusercontent.com/7atQm_Feen3n2HkSgCGgpFFMBccxO5ydEx2W1U-8JjxaxrUMWJ_flO5umeieHUSxCkZ9c4BwTS2LydXYGuhMDuPg5BTLNChYBsDJkJt8tyGjCOzGuIDilU5bWzzW_CZVLtKQMwQS5YAT2fWc6HuF1wA" alt /></p>
<p>Select the folder, make the template available for use, give it a unique name, and set the subject. The <em>Encoding</em> should be set to <em>Unicode (UTF-8)</em> as per HTML specifications. </p>
<p><img src="https://lh5.googleusercontent.com/jZODSM7lh1f5X6WXfcDKBmP1PN1iKWzGiZcnFhP250ez4UQIhGumru92GpU-iT0-J6gFIBQypnSPReWK2CRdLRbotmMVbHOFomutkzoXbOcDMfldlhckq9Iy8D07B2sgKYK23vUnBRkfrkA51yQAm6g" alt /></p>
<p>In the next step, we can add an HTML body. This time we’ll skip the merge field and concentrate on testing the HTML content. </p>
<p><img src="https://lh4.googleusercontent.com/1UlBvla_3jqwumoOFtntD7qN89RpL-FGZ7XcDvFVE-u60kcHlxswHe69U5BCnZJX7fcXyWxyXbBa_oL8EUh1uz8VNxX-EbvV3KuRgJ5gdnUXqJ1XWMTNINmc94GluRWzjQDsPX-ZerWOmtqMdwFMoi8" alt /></p>
<p>Then we need to configure the text version of the email. That way, the body text of the email will still be visible even if the email client doesn’t render the HTML properly. Click <em>Save.</em> </p>
<p><img src="https://lh4.googleusercontent.com/24PPRjcSaHke6xBdPCSPI9yQRH5R55cpgdwok9n4NoVMbz2ex96XNgW8Q8BNvsjs6pOrnpVUkXxy56cJVNsZlqcrjRUqHdn0IEEJmOU9g_ZIIusnW3RRH0aW6NK3twhTev_R7HCr2lassmmRKrlqyFA" alt /></p>
<p>You will see the preview of the email. Let’s send it as we did before and inspect it in our virtual inbox. </p>
<ol>
<li>Start by checking the email preview in different devices. You can check mobile, tablet, and desktop views. </li>
</ol>
<p><img src="https://lh5.googleusercontent.com/SSVD_IagNXnAJtGTLJ5Li2pCsLsz5yNnHC5aa8Hb7qdEM4IGA5IJXnYAn8vnw6gOY8Yb6cEKAmdRCuV5RV0_KLUndrigEa9MkNcL2vMFZExOZyLt2YIXEkT038k8ov_jGj1EcDlnrrVKTFEP4EvIHHs" alt /></p>
<ol start="2">
<li>Then let’s move to the <em>HTML Source</em> tab. There, you’ll see all the problematic elements marked with a red exclamation icon. </li>
</ol>
<p><img src="https://lh4.googleusercontent.com/JEaSlwO2pPa5s95W5Plds7Upw0n_Porxf0AgSTGyGzjdEdzEMFZkQxHBSxailsfxAOCH5m0IOh1VBeGlpRIUOepqJskGfslfzocvxo1m927VP41lpLb7Gdx7IvGdKjifbfypshQZovIzBRyTvsFTsQY" alt /></p>
<ol start="3">
<li>Go to the <em>HTML Check</em> tab to inspect client support in more detail. Here, you can filter results by a specific client/device or view the overall HTML support percentage. Check out our <a target="_blank" href="https://help.mailtrap.io/article/60-html-check">knowledge base article</a> to learn how HTML check works and how to interpret data. </li>
</ol>
<p>After analyzing the HTML check results, you can adjust the code and correct/remove elements that might stop your Salesforce emails from rendering in your contacts’ inboxes. </p>
<h2 id="heading-how-to-test-email-alerts"><strong>How to test email alerts</strong></h2>
<p>With Mailtrap, you can test any type of Salesforce email alert. The following sections detail all the steps, but we’ll start by creating an alert first. </p>
<ol>
<li>Search for <em>Email Alerts</em>, then click the <em>New Email Alert</em> button.</li>
</ol>
<p><img src="https://lh3.googleusercontent.com/Zf3QDlu7yP9YoE-tAcUvBqJ9xq1t36cE8O4F0NJHIRj3Jgb-HjaFZKA8XeKhAEDueSeQDu9c8vcf0og8F4xjJdqIkgfamm7vr9atJyF1Ei_HygJNbKbz5f_ul9rDTsaje6BrjLTuCZjKvKOJSWBrwJI" alt /></p>
<ol start="2">
<li>Fill out the fields based on your testing needs and click <em>Save</em>. Keep in mind that the fields labeled red are mandatory. Also, we used an exemplary object and email template, so you may need to change that based on your testing needs.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/Imc_nT0WLdVll58BWE1pqhtwS287kvGHLFB7ubGrY5FNRuZ_au4ntzSS2r0VKOie9dYNVpSVaGzXG1MoefEFgCs-APRZbnUBubw59Cx8rO7aawHiOrK7tWGlLm9j9Zc1DoRuJWk-Md2dCFz1bb93-6M" alt /></p>
<h3 id="heading-testing-email-alerts"><strong>Testing Email Alerts</strong></h3>
<p>An Email Alert can be sent via Workflow Rules, Process Builder, and the Flow. </p>
<p>Here are the steps for each method. </p>
<h3 id="heading-create-a-simple-workflow-rule"><strong>Create a simple Workflow rule</strong></h3>
<ol>
<li>Navigate to the <em>Workflow Rules</em> and click the <em>New Rule</em> button.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/6n6yFTi9bIztG3DiJEV3fEDE2rPnHJVoKEZxdOiDZ3-w7yIUtKd8PccQafyr7QXWfUkAJZW1tkYb0GDU5-BNBZiJtG2K9nE7nYbA5G5pELlSS-Vf2a2venddyMqqGdh4cX24zhbE5BF-ntO7mWMwT4Q" alt /></p>
<ol start="2">
<li>Select <em>Contact</em> as the object.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/guDDnP31oSfcpyOpalOfzZ10nxrwwGg8gBuCU4pyK-5uu0G-Tf_W-O7XdV55vQGJBtwvbI0w5_Hjosa7iBPxvsLj_Qxqo8EUgyPDLPnBOgEHXDZUNF_2qEyGMcRZzuIO61vkt7AtNAg4vkLWBSOKmG0" alt /></p>
<ol start="3">
<li>Under <em>Evaluation Criteria</em>, choose <em>created, and every time it’s added</em>. Then, in <em>Rule Criteria</em>, choose <em>Contact Email</em> under <em>Fields</em>, set the <em>Operator</em> to <em>not equal to</em>, and the <em>Value</em> as <em>null</em>. Lastly, click the <em>Save &amp; Next</em> button.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/r-ztyZX5P0DKnEJXb_L0W5v331_6-eAiMDue1LxbjH8rvnCCj-YM25RL6TNaN8ndrMxs1qcNSmyUDHM8N2j0_AqXbMY9d5Upu5br3mUCMjFiNKbZJxlYB3eezF66ppdm7FQ6mH9Dl0vF9Fhe5HuT_eU" alt /></p>
<ol start="4">
<li>Thereon, click the <em>Add Workflow Action</em> button and select <em>Existing Action</em>.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/zd8TE8KAll2iHtPURZJr-Lo3aRal7nt4wsdgMkAYvezON-70QL_SBMahhrk-g66cZPqzLoA7M8OBKKjLilnRg1bY0NEVTbq9Zhl_mfw3qGYYqj5n2uPF99h98BSkYdprnU2zxbiShEtHXTbM9ot_qdY" alt /></p>
<ol start="5">
<li>Choose the email alert that you previously created and click the <em>Save</em> button.</li>
</ol>
<p><img src="https://lh3.googleusercontent.com/bYqGw8d7HdPAtmWbVRCo84AOWkqC1aEzqLXFtvDEbBL4JlPFpmTWiAy3xVghpopM-pRBok_UbBCrO_JaQWC0_x7KC94AKO7QhLDknZPZJ-4rP5zdCXJjFfzzjBu5lK1ZnIIcn3YNNsJG_SbJIv3jkqE" alt /></p>
<ol start="6">
<li>Go to the <em>Workflow Rules</em> one more time and activate the process.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/PRrZw9wkHdH69LHI_3SFnN8Izwtv0KDIuHmTSzwm27STPpLND7uQwfAd5NnMxictwLCNR2hUCKTQETwrfEXMvYxEUJRCVAtrt3G_ojWmya9sz2Kw8jFsbyP5FU3jTC4ma3BLovzrsH6SS5pq2XvvzRs" alt /></p>
<h3 id="heading-test-the-workflow-rule-email-alert"><strong>Test the Workflow Rule Email Alert</strong></h3>
<ol>
<li>Go to any contact record and edit any field. The workflow rule should send an email alert when a contact record is created or edited. Then, click the <em>Save</em> button.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/CyGuFT7OK0IGtuKBo7vON3YjWoN7TEYx30TTJF0x8MDfIm9cG9X7-8Sszg-Z5kTcLcM473nrdjRAdOrBFkxG9MCT8CmuzIYJFnuDuC39S0LXSM3LPsMzl1qXLsI2BDOq-r2WfUq4rTN_cKYHhBPbPUk" alt /></p>
<ol start="2">
<li>Go to Mailtrap and make sure that the email is delivered.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/F-TxRYQcpcsP42c77RF1ryDfNvdDr1-qbeyJDZeMJ3yWr0RwRBTD6m_BJ0FgqDQnj_wPe3pFbVudFQvLMoyk8vC1lpir_bM58zTR1SgalAfPYnD4o1I6J_vjB4cCctd1j1WL4yDMsoSJnkZQy6h1Gp4" alt /></p>
<h3 id="heading-create-a-simple-process-builder"><strong>Create a simple Process Builder</strong></h3>
<ol>
<li>Navigate to the <em>Process Builder</em>, then click <em>New</em>.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/N53h9qRBhgL7XeMvB5E1XxPjdhx9CbBtSwAYUTbHeyLmasQxSImba4xE6vOUJpUQ3cbVkq0uuNzuyE5jryk6jyHu9TQqGrZIsPV3RABr9AWElUll5mUQjR9GyTzrrWtXl80P8_gaols2QAswAe6Rbd8" alt /></p>
<ol start="2">
<li>Fill out the fields based on your testing needs, and click the <em>Save</em> button.<br /> <strong>Tip:</strong> Make the Process, API name, and Description congruent for easier reference. Keep the variable under <em>The process starts when</em> at <em>A record changes.</em> </li>
</ol>
<p><img src="https://lh4.googleusercontent.com/vvZPc37eSsK73Mv470tCqOsc7qLtOIkbwFPqqeBcPpXZpbMVNWYSgDcovO7u0vteybReXTAMYYNsqdTDocAnXfsojVGJ_QEacBuykNm6jXVGrvZz-2fMRYLhP2bQ1Tu-9nPlwq7GN02wwIcqQx7dm18" alt /></p>
<ol start="3">
<li>Choose the Contact object and in the <em>Start the process</em> field select <em>only when a record is created</em> option, then click the <em>Save</em> button.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/H4ypw2fB9fF_2sQRNUPp3v85KvJPbPos4kUFUP7LF6wreQzE35MxTenz_8Q4vgbF-FdadDNWGJ-T4jHH06COukzmYH6BAs6kWQN3REn7VPGMSsy9KqIgxf5GKAoQN-lZSpeeSSwcHx7ZqjG4xcklO0E" alt /></p>
<ol start="4">
<li>Add <em>Criteria</em> based on your testing needs – we built the Process based on the example used in this article. </li>
</ol>
<p><img src="https://lh6.googleusercontent.com/tst_1rdZ1yoL5wfHxqcvnSPy107wWZQ-T96_Nh904Ira2Xvs5g77Jijrb0a7Ts_BXrZDnQDJgUpbKYExZAuFy7OvJshAi3qyYKkypED5-Bgs9Jzd1Sr9X0nXyXT-I_vbkbevsoej7S9RcXMTbs1_7mM" alt /></p>
<ol start="5">
<li>Click the <em>IMMEDIATE_ACTIONS</em> tile, and under the <em>Action Type</em> choose <em>Email Alerts</em>, then select the email alert created in the previous steps, and click the <em>Save</em> button.</li>
</ol>
<p><img src="https://lh3.googleusercontent.com/ITkjzOy8X6dMd12Jw2-LC9EX4aI_cHYTNgMHW64JP1ThC2cdiFGTDZjLFcpNa671inDIAcnWGKoRBiiZptYJPLg5s7NPbnAAiyv6fDSYhL7Y0LcdFz2be8H8kTCukuCZonxzPxfyqBnJFGFYzYZaTRM" alt /></p>
<ol start="6">
<li>Activate the Process Builder.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/xOTFF6TfWabK-4I5gp0EXe0-XPc0VMuAFYidhasBdwqa1Ljl8-C0MlVvxczrxbFFi8xRjPy3L6FgeNYmz6F4NHWrbXq_-jtXoE6tFUswT9CMkxUHAHZY7dHGMD3rJLi2KawES85ouWHjxX8NHZ-Hfd0" alt /></p>
<h3 id="heading-test-the-process-builder-email-alerts"><strong>Test the Process Builder Email Alerts</strong></h3>
<p><strong>Tip</strong>: If you want to get an email only from the Process Builder, deactivate Workflow rules before creating a new contact. Otherwise, the Workflow rule will be executed too as this rule also meets the criteria.</p>
<ol>
<li>Go to the <em>Contact</em> tab and create a new contact.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/u3cvU1OCSZvEydYeDD2bQugnWqpvyePxYFqwCDJw67Z-saHYE6Q0TZDwQOdtxCktgf6r1N_6xVL0Qw3_1QAAnHYBR0e1c8t5DAUHOlHkEoHZ4oo2VZvxbo1MA3f8KwIVwKKWG7z9EB5mMpYlJD9xjqk" alt /></p>
<ol start="2">
<li>Go to Mailtrap and make sure that the email is delivered.</li>
</ol>
<p><img src="https://lh3.googleusercontent.com/mbgXh3gnlWTBFX3Yk0yZzF-2u-WuiRh_X0MBdZ-vSjLLzD4nQ0PKpLUQQJTrCR181B59svAaHGEStvtyi-tpyWaxlyJmkzgG1TCQt3-j4jkwO5IsPo_Q3W03k12_yVqFFKjoyfDZS2H9waLQeEpXnZo" alt /></p>
<h3 id="heading-create-a-simple-flow"><strong>Create a simple flow</strong></h3>
<ol>
<li>Navigate to <em>Flows</em> and click the <em>New Flow</em> button.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/ffw2Ov0UZNOibBoDUrXUXGCOngv3yKuA-5cEswpxQcVir3IzM2aaDVxxyd1fq-OtNBCjC8OHydRucYUiVb4W3OnXsYYUB1MktiYzNNqgkW-Hen1hDe5No_kl9iggjUDX21PCYdN3U7W9_yoVcu9jZlU" alt /></p>
<ol start="2">
<li>Select <em>Record-Triggered Flow</em> and click the <em>Create</em> button.</li>
</ol>
<p><img src="https://lh5.googleusercontent.com/9IIqs0XcOG3-smqJVo215rC4XEboLeheHDBG352yLBEnttFrWLNxc8eob1XuisnYCSGFT1WPznRVOj2CWH0zUSt3Ie_1KTlszuUAoctjNiO3d8HkuiSS7o1QRiiekbfTDQdQ8IQMHcW_l6tUv_jdvd0" alt /></p>
<ol start="3">
<li>Configure Start as per your testing needs and click the <em>Done</em> button. Note that you should keep the <em>Configure Trigger</em> option as <em>A record is created or updated.</em> </li>
</ol>
<p><img src="https://lh3.googleusercontent.com/bNdK_b4RSAINoYCfZSZ_MREhlvBgjVK3yOuKV14pQQj5ZFPlKwTvWfR_NvYaFwPCW04genHWia-bTNjWFagfl6mNb1VkP77BCNmMlzojKFt379vcDyT829s5vAqhDzvsbD-lqjH5b6IJf3WhfoReer4" alt /></p>
<ol start="4">
<li>Click the white dot to add a new element.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/qnPOEfyC1nCXKEklnY7QufCOevYrIFXuSruj7BUPzs5cRTBEjHdOphdJX_r6GClj72tZq1FjmJXUHk4uV0Zo1wHUnnm_BIx7ToKfTHqylLy_osQR0Hfitg4R0183Mbp6QgV8iFZygqulvGRHOKPQW8c" alt /></p>
<ol start="5">
<li>Under <em>Shortcuts</em> choose <em>Send Email Alert</em>.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/HBbsbuS3cjB_RiDP4MQ0h-nMuWnn9Szg_C0jCWOVIqzKlO6kkO1kFrMUS1MIkBPApzW9Hx88OzG1hfizSUdAEUo4I_Bu5lhO7YlpoEoGZn_iyCtmI5WHugoGJ2W1Ckz92Qr1_C0_PBedWHHfHqre5-g" alt /></p>
<ol start="6">
<li>Fill out the fields to label and describe the action, then hit the <em>Done</em> button.</li>
</ol>
<p><img src="https://lh3.googleusercontent.com/pT9W67uNNRvZhQ0oZ7V9OFEB3rBUO-47e-tSy6GNDDNhMpxmPRh0MfBRjSHTTNrHDDGdm9Smev9ZKKoKEL8IVAKd0fg4IwUKqqmRQFmiJYx7rlD1gCnRGx1iqw8QOpFGvMfr3O2PnyK4vuT3DHhfxCA" alt /></p>
<ol start="7">
<li>Save the Flow. </li>
</ol>
<p><img src="https://lh5.googleusercontent.com/u02YbXOzu4fTwhKf9GAvskakMFBjlsplqg4H8Dcrw00mXXDUr0GM_klCE8tKoV7M4cS0KBMA7u5X2a7xsUSqcAOFCd-I1NURgjTMyZgMqzVUV2mMnSQ7uLRmeY3t4gWyDRAFH_FAZ1tH1qUCped8nhE" alt /></p>
<ol start="8">
<li>Activate the Flow.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/cqVLqyqHDD3nvpuETNPY9auwVlZZnLeoqHjMH8nkniooOaS8oLI3UCKL2N6bI8KyinvfUKFHBFsQh3aRjDnvWF7uYB4Hwxj2Xg2NwLbzuT9QdLMK20LCt93cSeR1vYMXc9eC13gpyv3JMttgQoybh6A" alt /></p>
<h3 id="heading-test-the-flow-email-alert"><strong>Test the Flow Email Alert</strong></h3>
<p><strong>Tip</strong>: If you want to get email only from Flow, deactivate Workflow rules and Process Builder before creating a new contact. Otherwise, the Workflow rule and Process Builder will also be executed as they meet the criteria.</p>
<ol>
<li>Go to the <em>Contact</em> tab and create a new contact.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/EQtAg-FGc5eIh3CuLYcr0z96rVi974GVzXqYvjxPCHsWQrMFYR7EIq_DUCP2jyHUWpHYcKCYNYa0M1IYWKuaiNseb5e-qXmXueJgX7_1wYZwf9UZTTXJjgwjxZGrAvPhpjoYz4HTzMtfwpUEuRP3i2Q" alt /></p>
<ol start="2">
<li>Go to Mailtrap and make sure that the email is delivered.</li>
</ol>
<p><img src="https://lh5.googleusercontent.com/E4fhaP5wJ2EuF8cbdKbwpT1I1ZTc9yipWwePnIT2Xqr1zDPvSsredDWcdTAQi98xjugVtGKZwkba6qwxSthR9wE4j2RtL_4EhJ32hERbaMGBGazgCMC3yuX6FVee2NxF_RGwFPvTUzpxtoGsO1kfKLA" alt /></p>
<h2 id="heading-how-to-test-bulk-email-handling"><strong>How to test bulk email handling</strong></h2>
<p>With the help of Mailtrap Email Testing, you can test bulk email handling in Salesforce. This test will validate the Apex limits and check if your bulk emails are getting delivered properly. </p>
<p>Just like with previous tests, Email Testing’s SMTP credentials should be set up as an email relay. </p>
<p>The first step is to create a sufficient amount of contact data by importing data with a <em>Data Import Wizard</em> or adding a couple of sample contacts manually. For the latter, press on the application icon and choose <em>Marketing.</em> </p>
<p><img src="https://lh5.googleusercontent.com/hb1YB4qqTcxKXNY2XkxysuTVAaW6zz698L-WH4g5IJdTF421NeAvEw0v92UKhs21bbDYcNRF7ZHFAO7GdUPjyFk6qVb4YPHBNascWnmG5oQ9GRp8pzX_0AZlwOZ3odklh8eKOTcaHm9iVXszMgfAbVg" alt /></p>
<p>Under the <em>Contacts</em> tab, click <em>New.</em> Enter the name of the contact, create a new account to associate with the contact, and enter the email address. Save the settings and repeat the process for any other contact you want to add. </p>
<p><img src="https://lh5.googleusercontent.com/CqKZGN5Va9N80TA7MyeeEr4q3WH05h9GQmdat8bl6HxtcTRJKj6V9NOcWA21qlPoCWTREogZwj6nPvFrz9AcclZOMTiFQuvbOscw5JmeEbNeviIZYOx4G32SiaKUWzelKGnQVIMTUeKkWJGgomuwm3I" alt /></p>
<p>Once you’re done, your contacts list should look something like this: </p>
<p><img src="https://lh6.googleusercontent.com/Pqvn2epTwC_ZHSpSmoY3hHBE7MIBTqA7RyMNyp3TPbi-ScWf56B_JvgbdpkmzYygUYotI_QKHirFOy9Wu7BVU6QotWBmv2AUpoQbJhUR6zTT1zj_uF5qrOBJcPtElKYkkP9IqraM0m7HB1d_DNfh4hE" alt /></p>
<p>Next, create a sample template, open it and note the template’s ID. It’s located in the URL and starts with 00X. </p>
<p><img src="https://lh6.googleusercontent.com/qQYnzHWDiiIzDZ2iID0fn149oKnuBJRoUmwRp-nde2v2lJHRY7oOqmz4ASFmSNb8v12BAq1y7gjt0aSI9_DYAFah9G13LreLgFJM4xC1J-hPjPp-Z3u17QQtTAhlu8CuaTHniSte8ymwh5H1OwFVwOs" alt /></p>
<p>At this point, we can start writing an Apex Class. </p>
<p>Add a new class in Apex classes with the following script: </p>
<pre><code class="lang-javascript">public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BulkEmailHandler</span> </span>{
    public <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> sendBulkEmail(List&lt;Id&gt; contactIds) {
        Messaging.reserveMassEmailCapacity(contactIds.size());

        Messaging.MassEmailMessage mail = <span class="hljs-keyword">new</span> Messaging.MassEmailMessage();

        mail.setTargetObjectIds(contactIds);
        mail.setTemplateId(<span class="hljs-string">'your_template_id'</span>); <span class="hljs-comment">// replace 'your_template_id' with the actual ID of your email template</span>
        mail.setSaveAsActivity(<span class="hljs-literal">false</span>);

        Messaging.sendEmail(<span class="hljs-keyword">new</span> Messaging.MassEmailMessage[] { mail });
    }
}
</code></pre>
<p><strong>Copy</strong></p>
<p>This piece of code requires contact IDs. So, to run the script, we should ask Apex to grab contact IDs first and then send an email. Open the developer console and in the <em>Open Execute Anonymous Window,</em> add the following lines: </p>
<pre><code class="lang-javascript">List&lt;Contact&gt; contacts = [SELECT Id FROM Contact LIMIT <span class="hljs-number">10</span>];
List&lt;Id&gt; contactIds = <span class="hljs-keyword">new</span> List&lt;Id&gt;();
<span class="hljs-keyword">for</span> (Contact c : contacts) {
    contactIds.add(c.Id);
}
BulkEmailHandler.sendBulkEmail(contactIds);
</code></pre>
<p><strong>Copy</strong></p>
<p>Press <em>Execute.</em> In a few seconds, the emails will pop up in your Mailtrap virtual inbox indicating that your Salesforce platform can successfully send bulk emails. </p>
<p><img src="https://lh4.googleusercontent.com/sNny1_IRzlAF5ar_qPabP5bERlPCn_ZTZTLsvH2cQQdB9W3AM_UTKreSRjXGqrZdfBG8ZapRSlD_UWriyCU_FJLfxoKSPmXj8_aeWntaZYLDXlOkrNoMhDtVJTF4BrIrLx_7OEeoMlOQ2WYzcXvyReo" alt /></p>
<p><em>Note: The code piece above will send an email to 50 contacts by default. You should update your SOQL query if you need to send more. Also, depending on the type of your Salesforce org and the package you’re using, your daily email sending volume may also be limited.</em> </p>
<h2 id="heading-wrapping-up"><strong>Wrapping up</strong></h2>
<p>This wraps up our tutorial on testing emails in Salesforce with Mailtrap Email Testing. Now you can successfully inspect and debug email deliverability, text and HTML templates, and bulk email handling. </p>
<p>Don’t forget to organize your virtual inbox by creating different projects and inboxes. That will simplify the testing process and keep your data in one place. </p>
<p>To learn more about Mailtrap, click <a target="_blank" href="https://mailtrap.io/">here</a>. </p>
<p><a target="_blank" href="https://mailtrap.io/register/signup?ref=header"><strong>Sign Up for Free</strong></a></p>
<p>We appreciate you chose this amazing article to know how to use Mailtrap with Salesforce to test emails. To read more interesting articles on the related topics, follow <a target="_blank" href="https://mailtrap.io/blog/salesforce-test-emails/">Mailtrap blog</a>!</p>
]]></content:encoded></item><item><title><![CDATA[How to Create an HTML Template That Email Clients Render Well]]></title><description><![CDATA[A developer can’t code an HTML email template using the same technologies and approaches as one would when building a web page. It may sound ridiculous, but it’s the truth. So, let’s try to figure out how valid this statement is.
Email clients with n...]]></description><link>https://ketevanbostoganashvili.hashnode.dev/how-to-create-an-html-template-that-email-clients-render-well</link><guid isPermaLink="true">https://ketevanbostoganashvili.hashnode.dev/how-to-create-an-html-template-that-email-clients-render-well</guid><category><![CDATA[HTML Emails]]></category><dc:creator><![CDATA[Ketevan Bostoganashvili]]></dc:creator><pubDate>Wed, 24 Jul 2024 06:31:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721802519193/50df59a1-bc1e-4c61-8e17-f2315cf7dc08.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A developer can’t code an HTML email template using the same technologies and approaches as one would when building a web page. It may sound ridiculous, but it’s the truth. So, let’s try to figure out how valid this statement is.</p>
<h2 id="heading-email-clients-with-no-standards"><strong>Email clients with no standards</strong></h2>
<p>While coding a web page, an engineer takes the following factors into consideration:</p>
<ul>
<li><p>operating system</p>
</li>
<li><p>browser type</p>
</li>
<li><p>screen size</p>
</li>
</ul>
<p>When building an HTML email template, in addition to the operating system and screen size, one has to account for the email client.</p>
<p>There is a wide selection of email clients that encompasses several web and desktop solutions, where the way an email is displayed depends largely on the rendering engine a system uses.</p>
<p>Of course, a universal set of standards would be much easier for email clients to support and for developers to comply with. But, unfortunately, we don’t have any. Every email client plays by its own rules. That’s why the rendering of CSS by various email clients may differ significantly.</p>
<h2 id="heading-top-10-email-clients-in-2018"><strong>Top 10 email clients in 2018</strong></h2>
<p>In June 2018, Litmus released an <a target="_blank" href="https://emailclientmarketshare.com/">Email Client Market Share report</a> which was based on 1.04B email opens data they gathered worldwide. One can review this report to get an idea about the core market players and their shares in this area.</p>
<p><em>Email Client Market Share, 2018</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2019/11/email_clients_market_share_20181-900x450.png" alt /></p>
<h2 id="heading-know-what-email-clients-your-target-audience-prefers"><strong>Know what email clients your target audience prefers</strong></h2>
<p>Although having access to the general stats provided by Litmus is great, we would recommend you check what devices and email clients your target audience uses. Having this information at hand will simplify the email development process by reducing the number of devices and email clients an engineer has to tailor an email for.</p>
<p>If you are using <strong>Mailchimp</strong>, go to <strong>List</strong> and check the following stats:</p>
<p><em>Email clients per sending list in Mailchimp</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2019/11/mailchimp_top_email_clients_per_list-900x287.png" alt="Email clients per sending list in Mailchimp" /></p>
<p>If you are using <strong>Sendgrid</strong>, go to <strong>Stats</strong>, and then <strong>Email Clients &amp; Devices</strong>. Sendgrid will provide you with several respective categories: Top Devices, Top Webmail Clients, and Top Desktop Clients.</p>
<p><em>The top devices used to open Mailtrap email campaigns in Sendgrid</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2019/11/sendgrid_top_devices-900x369.png" alt="The top devices used to open Mailtrap email campaigns  in Sendgrid " /></p>
<p><em>The top webmail clients used to open Mailtrap email campaigns in Sendgrid</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2019/11/sendgrid_top_webmail_clients-900x370.png" alt="The top webmail clients used to open Mailtrap email campaigns in Sendgrid" /></p>
<p><em>The top desktop email clients used to open Mailtrap email campaigns in Sendgrid</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2019/11/sendgrid_top_desktop_clients-900x371.png" alt="The top desktop email clients used to open Mailtrap email campaigns in Sendgrid" /></p>
<h3 id="heading-outlook-email-client"><strong>Outlook email client</strong></h3>
<p>According to the Litmus Email Client Market Share report, Outlook ranks #5 with a 7% market share. However, not everyone knows that Outlook for Windows still uses the Microsoft Word engine for rendering. At the same time, Outlook for Mac supports almost any kind of HTML and CSS formatting.</p>
<p>Below are only some of the aspects a developer should bear in mind when adjusting an email template for an Outlook email client:</p>
<ul>
<li><p>Outlook does not “understand” HTML bulleted list tags</p>
</li>
<li><p>Outlook uses Times New Roman as the default font</p>
</li>
<li><p>Outlook may add a page break to an email if it exceeds 1800px</p>
</li>
<li><p>Outlook cleans up paragraph and margin spacing</p>
</li>
<li><p>Outlook does not support background images</p>
</li>
</ul>
<p>Of course, some of the above-mentioned cases may be solved by using a “table<em>”</em> tag structure in an email template, while others require special tricks and workarounds that engineers may apply to ensure correct email rendering.</p>
<h2 id="heading-the-best-ways-to-create-html-emails"><strong>The best ways to create HTML emails</strong></h2>
<p>There are some aspects that one should consider when building <a target="_blank" href="https://beefree.io/templates/">HTML email templates</a>. Let’s review the suggestions below.</p>
<h3 id="heading-use-simple-design"><strong>Use simple design</strong></h3>
<p>We recommend developers keep the email design simple. Apply grid-based layers and stay away from the elements that include positioning or HTML floats.</p>
<h3 id="heading-adjust-html-emails-to-different-screen-sizes"><strong>Adjust HTML emails to different screen sizes</strong></h3>
<p>With Apple iPhone email client ranking #1 in the recent Litmus report, one can see clearly that it is crucial for an email template to display well not only on desktop but also on tablet and smartphone.<br />To succeed with this task, one can try using scalable, fluid, or responsive design. So, let’s dive a bit deeper into each type of design to choose the one which will suit your requirements best.</p>
<h4 id="heading-scalable-html-email-design"><strong>Scalable HTML email design</strong></h4>
<p>This type of design presumes the presence of a minimum number of structural elements in an email. That’s why it usually consists of one text column that can be easily scaled for all types of devices, one image, and a Call to Action (CTA) button.</p>
<h4 id="heading-fluid-html-email-design"><strong>Fluid HTML email design</strong></h4>
<p>The fluid design uses percentages to adjust to a recipient’s screen size by filling up all space in an email just like fluid would do in an empty container. However, to make sure an email’s content does not cover all the available screen area, it is recommended to configure the table’s maximum width. It’s a common practice to set the default width to 600px.</p>
<h4 id="heading-responsive-html-email-design"><strong>Responsive HTML email design</strong></h4>
<p>Utilizing responsive design, in turn, allows sending customized HTML email templates that may automatically adjust not only the size but also the content depending on a recipient’s device and screen size. The desktop and the mobile version of an email may differ significantly from each other or may be alike. In the end, a desktop version of an email may include more or different components than a mobile version and vice versa, which makes this type of design universal for all devices and screen sizes (existing and newly introduced).</p>
<p>Media queries, introduced in CSS3, empower responsive design. The top email clients are well aware of what media queries are. However, it’s worth keeping in mind that there are still email clients that won’t succeed with their rendering at all.</p>
<h3 id="heading-think-about-mobile-users"><strong>Think about mobile users</strong></h3>
<p>Working with HTML email design, one should remember the golden rule – mobile design goes first. I.e., a mobile version should be checked first to decrease the loading time on small devices. For instance, the first condition may be set as “larger than 768 pixels”.</p>
<h3 id="heading-choose-the-right-fonts"><strong>Choose the right fonts</strong></h3>
<p>Many email clients won’t be able to render Google Fonts properly. In this case, one should opt for the common fonts that the major email clients interpret well. Such as Times New Roman, Arial, Georgia, and Verdana.</p>
<h3 id="heading-take-images-seriously"><strong>Take images seriously</strong></h3>
<p>Some email clients block images by default and some users may amend their inbox settings to block images if the client isn’t doing it. So, it is best to follow the advice below when coding an email template:</p>
<ul>
<li><p>Accompany your image header with text to make sure that a user will still understand what the email is about, even if the image gets blocked.</p>
</li>
<li><p>Don’t build HTML emails that consist of one or two large images only. If one of them or both are not displayed properly, it will ruin the entire email campaign.</p>
</li>
<li><p>Keep your emails simple by adding just enough images and text to guarantee that your message still makes sense even if all images are blocked.</p>
</li>
<li><p>If your email includes a call to action (CTA) in the form of a button, don’t use an image to format the CTA. Instead, you can try to create a padding-based button. This simple method uses both HTML and CSS for button building.</p>
</li>
</ul>
<p>Last but not least: keep in mind the email size. The <a target="_blank" href="https://mailtrap.io/blog/email-size/">maximum file size limits for emails</a> are pretty high, but the recommended size of the email body should not exceed 250KB.</p>
<p>For more development tips and code samples, check our <a target="_blank" href="https://mailtrap.io/blog/build-html-email/">guide on building HTML Email</a>.</p>
<p>Otherwise, you can try using an HTML email builder. They usually come with a set of customizable email templates, which can be used in any email sending system. In <a target="_blank" href="https://mailtrap.io/blog/best-email-builders/">this post</a>, we have reviewed the ten tools suitable for both developers’ and marketers’ needs.</p>
<h2 id="heading-html-email-testing"><strong>HTML email testing</strong></h2>
<p>Before sending out an HTML email campaign, it is worth checking whether your emails will get delivered to recipients or end up marked as spam, as well as getting some email rendering advice.</p>
<p>For this, we recommend using a solution such as <a target="_blank" href="https://mailtrap.io/email-sandbox/">Mailtrap Email Sandbox</a>, which provides you with a safe environment for inspecting and debugging testing emails, so you don’t accidentally end up spamming recipients.</p>
<p>Mailtrap Email Sandbox comes in especially handy for testing HTML emails as it provides a range of features intended specifically for this purpose. So, once you send your first test email to Mailtrap Email Sandbox (process described in detail <a target="_blank" href="https://help.mailtrap.io/article/12-getting-started-guide#:~:text=Email%20Sandbox%20%3CTest%3E-,How%20to%20send%20a%20test%20email%20to%20Mailtrap%20Sandbox,-There%20are%20three">here</a>), you will be able to:</p>
<ul>
<li>View how your email is rendered by a browser and check its responsiveness in the <strong>HTML</strong> tab.</li>
</ul>
<p><em>Mailtrap Email Sandbox HTML tab</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2022/12/email-sandbox-html-tab.png" alt /></p>
<ul>
<li>Scan through your email’s HTML code for problematic elements, gain insight into which email clients don’t support or only partially support those problematic elements. Furthermore, in the <strong>HTML Check</strong> tab, you can get an estimate of how your email code is supported across popular email clients.</li>
</ul>
<p><em>Mailtrap Email Sandbox HTML Check tab</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2022/12/email-sandbox-html-check-feature.png" alt /></p>
<ul>
<li>View the HTML markup in the <strong>HTML Source</strong> tab.</li>
</ul>
<p><em>Mailtrap Email Sandbox HTML Source tab</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2022/12/email-sandbox-html-source-tab.jpg" alt /></p>
<ul>
<li>View the email’s text part (the message displayed when the HTML cannot be) in the <strong>Text</strong> tab.</li>
</ul>
<p><em>Mailtrap Email Sandbox Text tab</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2022/12/email-sandbox-text-tab.png" alt /></p>
<ul>
<li>Preview the email in raw format in the <strong>Raw</strong> tab.</li>
</ul>
<p><em>Mailtrap Email Sandbox Raw tab</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2022/12/email-sandbox-raw-tab.jpg" alt /></p>
<p>Other features of Mailtrap Email Sandbox include multiple virtual inboxes for different projects and project stages, blacklist reports for your sender IP/domain, spam analysis, manual and automatic email forwarding to whitelisted recipients, and insight into detailed tech info – essentially everything one needs for advanced email testing.</p>
<p>To get started with this solution, all you need to do is sign up for a free <a target="_blank" href="https://mailtrap.io/register/signup">Mailtrap account</a> and complete a 5-minute setup. After that, you can start exploring all the mentioned Email Sandbox features.</p>
<p><a target="_blank" href="https://mailtrap.io/register/signup"><strong>Inspect Your Emails</strong></a></p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>We hope that this blog post addressed some of the core aspects you should be paying attention to when crafting an email template. In addition, we just wanted to remind you one more time how important HTML emails testing is 😉</p>
<p>We appreciate you chose this article to know how to build HTML email template. To read more article on related topics, follow <a target="_blank" href="https://mailtrap.io/blog/building-html-email-template/">Mailtrap blog</a>!</p>
]]></content:encoded></item><item><title><![CDATA[How to Send HTML Emails in PHP]]></title><description><![CDATA[PHP has multiple options for sending HTML emails: the PHP mail() function, PHPMailer, or SymfonyMailer. However, the latter two are the more popular and recommended options.
Why? Because the PHP mail() function has multiple limitations, including the...]]></description><link>https://ketevanbostoganashvili.hashnode.dev/how-to-send-html-emails-in-php</link><guid isPermaLink="true">https://ketevanbostoganashvili.hashnode.dev/how-to-send-html-emails-in-php</guid><category><![CDATA[PHP]]></category><category><![CDATA[email templates]]></category><dc:creator><![CDATA[Ketevan Bostoganashvili]]></dc:creator><pubDate>Wed, 06 Mar 2024 15:12:06 GMT</pubDate><content:encoded><![CDATA[<p>PHP has multiple options for sending HTML emails: the PHP mail() function, PHPMailer, or SymfonyMailer. However, the latter two are the more popular and recommended options.</p>
<p>Why? Because the PHP mail() function has multiple limitations, including the inability to add attachments or send emails using the SMTP server. I’ll be diving into more details on the limitations below. </p>
<p>In this tutorial, I’ll show you how to build and send HTML emails in PHP using the mail() function, PHPMailer, and SymfonyMailer. I’ll also show you how to leverage Mailtrap’s SDK to send beautiful HTML emails in PHP. Let’s go! </p>
<h2 id="heading-send-html-emails-using-phps-mail-function"><strong>Send HTML emails using PHP’s mail() function</strong></h2>
<p>I’ll start with mail(), as it’s a native function in PHP. With it, you can send plain text and simple HTML emails. First, I’ll list its limitations and then provide code pieces for sending HTML emails. </p>
<h3 id="heading-limitations-of-php-mail-function"><strong>Limitations of PHP mail() function</strong></h3>
<p>PHP mail function might be simple, but there are several things it won’t allow you to do: </p>
<ul>
<li><p>You won’t be able to add attachments without complex configurations;</p>
</li>
<li><p>You won’t be able to embed images directly within the email as attachments that can be referenced in the HTML content via CID (Content ID); </p>
</li>
<li><p>You’ll have trouble sending emails to multiple recipients as the mail() function opens and closes the SMTP socket for each sent email. This can be time-consuming and resource-intensive. </p>
</li>
<li><p>You’ll have trouble connecting to third-party SMTP servers as the mail() function sends emails over the local server. And, for the same reason, you’ll most likely encounter deliverability issues (even if you’ve correctly configured SPF, DKIM, and DMARC and followed deliverability best practices). </p>
</li>
</ul>
<p>Considering the limitations and security concerns, mail() function isn’t a preferable option to send emails from PHP. But, if you still want to use it, I’ll show you how in the next section. <a target="_blank" href="https://mailtrap.io/blog/php-email-sending/">Read this blog post</a> or <a target="_blank" href="https://www.youtube.com/watch?v=f8oxbmJY7Jw">watch this video</a> for a detailed overview of sending emails in PHP. </p>
<h3 id="heading-send-a-simple-html-email"><strong>Send a simple HTML email</strong></h3>
<p>The built-in mail() function requires four arguments: the recipient’s email address, the subject of the email, the message, and additional headers. The additional headers allow us to set the <code>Content-type</code> header and specify it as <code>text/html</code>. </p>
<p>Sometimes, extra headers are used to specify the <code>'X-Mailer: PHP/' . phpversion()</code> header. This can be useful for debugging but could reveal your server configurations. For that reason, I decided to omit it. </p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

$to = <span class="hljs-string">'contact@example.com'</span>;
$subject = <span class="hljs-string">'Hello!'</span>;

$headers[<span class="hljs-string">'From'</span>] = <span class="hljs-string">'sender@example.com'</span>;
$headers[<span class="hljs-string">'MIME-Version'</span>] = <span class="hljs-string">'MIME-Version: 1.0'</span>;
$headers[<span class="hljs-string">'Content-type'</span>] = <span class="hljs-string">'text/html; charset=iso-8859-1'</span>

$message = <span class="hljs-string">'
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Review Request Reminder&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;p&gt;Here are the cases requiring your review in December:&lt;/p&gt;
    &lt;table&gt;
        &lt;tr&gt;
            &lt;th&gt;Case title&lt;/th&gt;&lt;th&gt;Category&lt;/th&gt;&lt;th&gt;Status&lt;/th&gt;&lt;th&gt;Due date&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Case 1&lt;/td&gt;&lt;td&gt;Development&lt;/td&gt;&lt;td&gt;pending&lt;/td&gt;&lt;td&gt;Dec-20&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Case 2&lt;/td&gt;&lt;td&gt;DevOps&lt;/td&gt;&lt;td&gt;pending&lt;/td&gt;&lt;td&gt;Dec-21&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;
'</span>;

$result = mail($to, $subject, $message, $headers);

<span class="hljs-keyword">if</span> ($result) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Success!'</span> . PHP_EOL;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Error.'</span> . PHP_EOL;
}
</code></pre>
<p>I also added error handling. The if statement checks if the email is sent successfully and provides feedback based on the outcome. </p>
<p>I ran this PHP code with <code>php send-mail.php</code>command and got the <em>Success!</em> message. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/03/image.png" alt="Success message received after running the php code successfully " /></p>
<p>Keep in mind that, despite the success message, the email still might not arrive in the indicated inbox. That’s because of the limitations we listed above. Also, the code will work only with specific configurations (with a local server or with a WordPress setup that doesn’t require third-party SMTP connections through TLS).</p>
<h3 id="heading-send-an-html-email-with-images-embedding-with-base64"><strong>Send an HTML email with images (embedding with base64)</strong></h3>
<p>To send an email with HTML content that includes images, we need to encode the image with base64. This will transform the binary data of the image into a text string, and we’ll be able to embed it into the HTML code using the <code>&lt;img&gt;</code> HTML tag. </p>
<p>But, before moving on to embedding, I’ll add simple error checking to ensure that the file exists and is readable. Then I’ll encode it.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment">// Check if the image file exists and is readable</span>
$imagePath = <span class="hljs-string">'path/to/your/image.jpg'</span>;
<span class="hljs-keyword">if</span> (file_exists($imagePath) &amp;&amp; is_readable($imagePath)) {
    <span class="hljs-comment">// Convert your image to base64 string</span>
    $imageData = base64_encode(file_get_contents($imagePath));
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Image file not found or not accessible."</span>;
    <span class="hljs-keyword">exit</span>; <span class="hljs-comment">// Stop the script execution if the image is not accessible</span>
}
</code></pre>
<p>In the script above, the code will be executed only if both conditions are met, i.e., the image file exists and is readable. </p>
<p>The next step is to construct HTML content as in the previous example, but this time, I’ll add the <code>&lt;img&gt;</code> tag. </p>
<pre><code class="lang-php">$message = <span class="hljs-string">'
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Your Email Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;Here is the content of your email.&lt;/p&gt;
&lt;img src="data:image/jpeg;base64,'</span> . $imageData . <span class="hljs-string">'" alt="Description of Image"&gt;
&lt;/body&gt;
&lt;/html&gt;
'</span>;
</code></pre>
<p>Finally, I’ll set the headers and send an email. The headers should be separated with CRLF (\r\n). The complete code snippet will look like this: </p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-comment">// Check if the image file exists and is readable</span>
$imagePath = <span class="hljs-string">'path/to/your/image.jpg'</span>;
<span class="hljs-keyword">if</span> (file_exists($imagePath) &amp;&amp; is_readable($imagePath)) {
    <span class="hljs-comment">// Convert your image to base64 string</span>
    $imageData = base64_encode(file_get_contents($imagePath));
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Image file not found or not accessible."</span>;
    <span class="hljs-keyword">exit</span>; <span class="hljs-comment">// Stop the script execution if the image is not accessible</span>
}

<span class="hljs-comment">// Construct the HTML email content</span>
$message = <span class="hljs-string">'
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Your Email Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;Here is the content of your email.&lt;/p&gt;
&lt;img src="data:image/jpeg;base64,'</span> . $imageData . <span class="hljs-string">'" alt="Description of Image"&gt;
&lt;/body&gt;
&lt;/html&gt;
'</span>;

<span class="hljs-comment">// Set the headers</span>
$headers = [
    <span class="hljs-string">"MIME-Version: 1.0"</span>,
    <span class="hljs-string">"Content-type: text/html; charset=UTF-8"</span>,
    <span class="hljs-string">'From: Your Name &lt;sender@example.com&gt;'</span>,
    <span class="hljs-string">'Cc: Another Name &lt;another-email@example.com&gt;'</span>,
];

<span class="hljs-comment">// Send the email</span>
<span class="hljs-keyword">if</span> (mail(<span class="hljs-string">'recipient@example.com'</span>, <span class="hljs-string">'Subject of Your Email'</span>, $message, implode(<span class="hljs-string">"\r\n"</span>, $headers))) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Email sent successfully."</span>;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed to send email."</span>;
}
<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>Keep in mind that this method increases the email size significantly. Larger email size can lead to a couple of problems: </p>
<ol>
<li><p>Slower loading times;</p>
</li>
<li><p>Email servers rejecting emails due to their larger size; </p>
</li>
<li><p>Email clients blocking base64 encoded images for security reasons. </p>
</li>
</ol>
<h3 id="heading-send-an-html-email-with-images-hosting-images-on-the-server"><strong>Send an HTML email with images (hosting images on the server)</strong></h3>
<p>Another option for embedding images when using the mail() function is to host images on the server. Unlike base64, this method doesn’t increase the email size. </p>
<p>Here’s how to do it: </p>
<ol>
<li><p>Upload the image to your web server. Make sure it’s uploaded to a publicly accessible location. </p>
</li>
<li><p>Reference the image in your HTML content using the <code>&lt;img&gt;</code> tag and its absolute URL: </p>
</li>
</ol>
<pre><code class="lang-php">&lt;img src=<span class="hljs-string">"https://www.yourdomain.com/images/your-image.jpg"</span> alt=<span class="hljs-string">"Embedded Image"</span>&gt;
</code></pre>
<ol start="3">
<li>Send the email with the mail() function as we did with the previous example. </li>
</ol>
<p>The complete code snippet will look something like this: </p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

$to = <span class="hljs-string">'recipient@example.com'</span>;
$subject = <span class="hljs-string">'Email with Embedded Image'</span>;
$message = <span class="hljs-string">'
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Email with Embedded Image&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;p&gt;Here is an image embedded in this email:&lt;/p&gt;
  &lt;img src="https://www.yourdomain.com/images/your-image.jpg" alt="Embedded Image"&gt;
&lt;/body&gt;
&lt;/html&gt;
'</span>;

$headers = <span class="hljs-string">"MIME-Version: 1.0"</span> . <span class="hljs-string">"\r\n"</span>;
$headers .= <span class="hljs-string">"Content-type:text/html;charset=UTF-8"</span> . <span class="hljs-string">"\r\n"</span>;

$headers .= <span class="hljs-string">'From: &lt;sender@example.com&gt;'</span> . <span class="hljs-string">"\r\n"</span>;
$headers .= <span class="hljs-string">'Reply-To: &lt;sender@example.com&gt;'</span> . <span class="hljs-string">"\r\n"</span>;

<span class="hljs-keyword">if</span>(mail($to, $subject, $message, $headers)) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Email sent successfully."</span>;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed to send email."</span>;
}
<span class="hljs-meta">?&gt;</span>
</code></pre>
<h2 id="heading-send-html-emails-using-phpmailer"><strong>Send HTML emails using PHPMailer</strong></h2>
<p>A better way to send HTML emails in PHP is by using <a target="_blank" href="https://github.com/PHPMailer/PHPMailer">PHPMailer</a>. This package addresses the limitations of the native mail() function. It has features such as: </p>
<ul>
<li><p>SMTP authentication;</p>
</li>
<li><p>Support for TLS and SSL protocols;</p>
</li>
<li><p>Image embedding;</p>
</li>
<li><p>Adding attachments;</p>
</li>
<li><p>The ability to connect to external SMTP servers;</p>
</li>
<li><p>And, most importantly (at least for this blog post), the ability to send text and HTML emails.</p>
</li>
</ul>
<p>First, I’ll install the package by adding the following line to the <em>composer.json</em> file: </p>
<pre><code class="lang-php"><span class="hljs-string">"phpmailer/phpmailer"</span>: <span class="hljs-string">"^6.9.1"</span>
</code></pre>
<p>Alternatively, you can run the <code>composer require phpmailer/phpmailer</code> command. </p>
<p>To send and deliver HTML emails with PHPMailer, I’ll use a third-party SMTP provider – <a target="_blank" href="https://mailtrap.io/email-sending/">Mailtrap Email Sending</a>, which is a sending solution with high deliverability rates by design.</p>
<p>Email Sending provides separate streams for bulk and transactional emails to maintain high and stable deliverability. While it has an official PHP SDK, I’ll focus on its SMTP server for now. </p>
<h3 id="heading-send-a-basic-html-message"><strong>Send a basic HTML message</strong></h3>
<p>Sending a basic HTML message using PHPMailer is pretty straightforward. First, start your new PHP project with the following code: </p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">PHPMailer</span>\<span class="hljs-title">PHPMailer</span>\<span class="hljs-title">PHPMailer</span>;
</code></pre>
<p>And include the Composer-generated <em>autoload.php</em> file. </p>
<pre><code class="lang-php"><span class="hljs-keyword">require</span> <span class="hljs-string">'path/to/composer/vendor/autoload.php'</span>;
</code></pre>
<p>Create a new instance of the PHPMailer class and configure the SMTP settings. </p>
<pre><code class="lang-php">$mail = <span class="hljs-keyword">new</span> PHPMailer();
$mail-&gt;isSMTP();
$mail-&gt;Host = <span class="hljs-string">'smtp.example.com'</span>;
$mail-&gt;SMTPAuth = <span class="hljs-literal">true</span>;
$mail-&gt;Username = <span class="hljs-string">'1a2b3c4d5e6f7g'</span>;
$mail-&gt;Password = <span class="hljs-string">'1a2b3c4d5e6f7g'</span>;
$mail-&gt;SMTPSecure = <span class="hljs-string">'tls'</span>;
$mail-&gt;Port = <span class="hljs-number">2525</span>;
</code></pre>
<p>For this step, I had to go to my Mailtrap account and grab the necessary credentials. I’ve already added and verified the sending domain, but if you haven’t done so yet, check out the <a target="_blank" href="https://help.mailtrap.io/article/69-sending-domain-setup">sending domain setup article</a> for detailed instructions. </p>
<p>Once the domain is verified, go to Sending Domains, click on the verified domain, and open the <em>SMTP/API Settings</em> tab. There, you’ll see Transactional Stream and Bulk Stream. In this case, I’ll opt for a Transactional Stream and copy the credentials underneath. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/03/image-9.png" alt /></p>
<p>This is what the code piece above will look like once you configure it with Mailtrap SMTP settings. </p>
<pre><code class="lang-php">$mail = <span class="hljs-keyword">new</span> PHPMailer();
$mail-&gt;isSMTP();
$mail-&gt;Host = <span class="hljs-string">'live.smtp.mailtrap.io'</span>;
$mail-&gt;SMTPAuth = <span class="hljs-literal">true</span>;
$mail-&gt;Username = <span class="hljs-string">'api'</span>;
$mail-&gt;Password = <span class="hljs-string">'YOUR_API_TOKEN'</span>
$mail-&gt;SMTPSecure = <span class="hljs-string">'tls'</span>;
$mail-&gt;Port = <span class="hljs-number">587</span>;
</code></pre>
<p>Specify the headers. Indicate the sending email address containing the verified domain using the <code>setFrom</code> method. Set the recipient’s email address with the <code>addAddress</code> method. Then, add the subject line using the <code>Subject</code> property. </p>
<pre><code class="lang-php">$mail-&gt;setFrom(address: <span class="hljs-string">'sender@example.com'</span>, name: <span class="hljs-string">'Kate'</span>);
$mail-&gt;addAddress(address: <span class="hljs-string">'recipient@example.com'</span>, name: John);
$mail-&gt;Subject = <span class="hljs-string">'Your Email Subject!'</span>;
</code></pre>
<p>Set the email format to HTML using the <code>isHTML</code> property and add the HTML content. Use the <code>AltBody</code> property to indicate the text version of the email. </p>
<pre><code class="lang-php">$mail-&gt;isHTML(isHtml: <span class="hljs-literal">TRUE</span>);
$mail-&gt;Body = <span class="hljs-string">'&lt;html&gt;Hi there, we are happy to &lt;br&gt;confirm your booking.&lt;br&gt;Please check the document in the attachment.&lt;/html&gt;'</span>;
$mail-&gt;AltBody = <span class="hljs-string">'Hi there, we are happy to confirm your booking. Please check the document in the attachment.'</span>;
</code></pre>
<p>Finally, send the email using the <code>send</code> method. </p>
<pre><code class="lang-php"><span class="hljs-keyword">if</span> (!$mail-&gt;send()) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Message could not be sent.'</span>;
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Mailer Error: '</span> . $mail-&gt;ErrorInfo;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Message has been sent'</span>;
}
</code></pre>
<p>Check out the whole sample below: </p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">PHPMailer</span>\<span class="hljs-title">PHPMailer</span>\<span class="hljs-title">PHPMailer</span>;

<span class="hljs-keyword">require</span> <span class="hljs-string">'path/to/composer/vendor/autoload.php'</span>;

$mail = <span class="hljs-keyword">new</span> PHPMailer();
$mail-&gt;isSMTP();
$mail-&gt;Host = <span class="hljs-string">'live.smtp.mailtrap.io'</span>;
$mail-&gt;SMTPAuth = <span class="hljs-literal">true</span>;
$mail-&gt;Username = <span class="hljs-string">'api'</span>;
$mail-&gt;Password = <span class="hljs-string">'YOUR_API_TOKEN'</span>;
$mail-&gt;SMTPSecure = <span class="hljs-string">'tls'</span>;
$mail-&gt;Port = <span class="hljs-number">587</span>;

$mail-&gt;setFrom(address: <span class="hljs-string">'sender@example.com'</span>, name: <span class="hljs-string">'Kate'</span>);
$mail-&gt;addAddress(address: <span class="hljs-string">'recipient@example.com'</span>, name: <span class="hljs-string">'John'</span>);
$mail-&gt;Subject = <span class="hljs-string">'Your Email Subject!'</span>;

$mail-&gt;isHTML(<span class="hljs-literal">true</span>);
$mail-&gt;Body = <span class="hljs-string">'&lt;html&gt;Hi there, we are happy to &lt;br&gt;confirm your booking.&lt;br&gt;Please check the details.&lt;/html&gt;'</span>;
$mail-&gt;AltBody = <span class="hljs-string">'Hi there, we are happy to confirm your booking. Please check the details.'</span>;

<span class="hljs-keyword">if</span> (!$mail-&gt;send()) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Message could not be sent.'</span>;
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Mailer Error: '</span> . $mail-&gt;ErrorInfo;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Message has been sent'</span>;
}
<span class="hljs-meta">?&gt;</span>
</code></pre>
<p>Run the script with <code>php send–mail-php-mailer.php</code> command. The HTML email message should appear in the recipient’s inbox if you did everything correctly. </p>
<h3 id="heading-send-an-html-email-with-an-embedded-image"><strong>Send an HTML email with an embedded image</strong></h3>
<p>When it comes to embedding, you have a couple of options: base64 encoding (similar to how I did it with native PHP script), CID (Content ID), and linking images hosted on a web server. </p>
<p>Each method has its drawbacks, but CID is still a recommended option. It involves attaching an image and referencing it in HTML with CID. </p>
<p>So, to the previous PHP code, I’ll add <code>addEmbeddedImage</code> method. I’ll pass the image path and CID to it. </p>
<pre><code class="lang-php">$mail-&gt;addEmbeddedImage(<span class="hljs-string">'path/to/image.jpg'</span>, <span class="hljs-string">'image_cid'</span>);
</code></pre>
<p>Then, I’ll include it in the src attribute of the <code>&lt;img&gt;</code> tag. </p>
<pre><code class="lang-php">$mail-&gt;isHTML(<span class="hljs-literal">true</span>); <span class="hljs-comment">// Set email format to HTML</span>
$mail-&gt;Subject = <span class="hljs-string">'Here is the subject'</span>;
$mail-&gt;Body    = <span class="hljs-string">'
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Your Booking Confirmation&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;p&gt;Hi there, we are happy to &lt;br&gt;confirm your booking.&lt;br&gt;Please check the details:&lt;/p&gt;
    &lt;img src="cid:image_cid"&gt;
&lt;/body&gt;
&lt;/html&gt;'</span>;
</code></pre>
<h3 id="heading-send-an-html-email-with-attachments"><strong>Send an HTML email with attachments</strong></h3>
<p>To include an attachment in your HTML-formatted email, simply add the following lines of code after the HTML/text portion: </p>
<pre><code class="lang-php">$attachmentPath = <span class="hljs-string">'./confirmations/yourbooking.pdf'</span>;
<span class="hljs-keyword">if</span> (file_exists($attachmentPath)) {
    $mail-&gt;addAttachment($attachmentPath, name: <span class="hljs-string">'yourbooking.pdf'</span>);
}
</code></pre>
<p>If you want to add multiple attachments, repeat the code above as many times as you need. Don’t forget to specify the exact paths for each file. </p>
<h3 id="heading-send-html-emails-to-multiple-recipients"><strong>Send HTML emails to multiple recipients</strong></h3>
<p>With PHPMailer, you can easily send HTML emails to multiple recipients. I’ll loop through an array of recipients and use the <code>addAddress()</code>method for each. </p>
<pre><code class="lang-php">$recipients = [
    [<span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'recipient1@example.com'</span>, <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'John Doe'</span>],
    [<span class="hljs-string">'email'</span> =&gt; <span class="hljs-string">'recipient2@example.com'</span>, <span class="hljs-string">'name'</span> =&gt; <span class="hljs-string">'Jane Doe'</span>],
    <span class="hljs-comment">// Add more recipients as needed</span>
];

<span class="hljs-keyword">foreach</span> ($recipients <span class="hljs-keyword">as</span> $recipient) {
    $mail-&gt;addAddress($recipient[<span class="hljs-string">'email'</span>], $recipient[<span class="hljs-string">'name'</span>]);
}
</code></pre>
<p><code>$recipients</code> is an array that contains the email addresses and names of all the recipients. The <code>foreach</code> loop iterates over this array, adding each recipient to the email. When I call the <code>send()</code> method, the email will be sent to each added recipient. </p>
<p>The rest of the code sample will essentially be the same as in the previous example. </p>
<p>If you want to send other types of emails, read the <a target="_blank" href="https://mailtrap.io/blog/phpmailer/">full tutorial on PHPMailer</a>. <a target="_blank" href="https://mailtrap.io/blog/phpmailer-gmail/">Check out this blog post</a> to learn how to send emails with PHPMailer and Gmail SMTP server. </p>
<h2 id="heading-send-html-emails-using-mailtrap-php-client"><strong>Send HTML emails using Mailtrap PHP Client</strong></h2>
<p>An easy way to build and send complex HTML emails in PHP is <a target="_blank" href="https://github.com/railsware/mailtrap-php?tab=readme-ov-file">Mailtrap PHP Client</a>. It’s fully compatible with Laravel and Symfony frameworks and allows you to choose the desired HTTP client. </p>
<p>With Mailtrap PHP SDK, you can also send HTML emails in PHP using templates. You can store the templates in Mailtrap and reference them through API. <a target="_blank" href="https://help.mailtrap.io/article/105-email-templates">Read this article</a> for more information on template features and usages. </p>
<p><em>Note: At the time of writing, templates are available for transactional emails only.</em> <em>Soon, they will also be available for bulk emails.</em> </p>
<h3 id="heading-send-html-emails-without-templates"><strong>Send HTML emails without templates</strong></h3>
<p>First, I’ll show you how to send HTML emails without templates. But, before sending the emails, I need to grab the API key from Mailtrap and store it securely in the <em>.env</em> file. </p>
<p>To access your API key, in your Mailtrap account, go to Settings → API Tokens, and click the <em>Add Token</em> button. </p>
<p>Choose the verified domain you want to send emails from, add the desired name, and click <em>Save</em>. </p>
<p>The API token will appear on the API Tokens page. Simply copy it. Return to your PHP project and create a <em>.env</em> file in the root directory. Add your Mailtrap API key to this file like so:</p>
<pre><code class="lang-php"><span class="hljs-comment"># .env file</span>
MAILTRAP_API_KEY=your_mailtrap_api_key
</code></pre>
<p>Then, update your <em>.gitignore</em> file to exclude the <em>.env</em> file from version control and protect sensitive data. </p>
<p>At this point, we can install Mailtrap PHP Client. If you’re using Symfony HTTP client, use this command: </p>
<pre><code class="lang-php">composer <span class="hljs-keyword">require</span> railsware/mailtrap-php symfony/http-client nyholm/psr7
</code></pre>
<p>For the Guzzle HTTP client, install the package by running the following line of code: </p>
<pre><code class="lang-php">composer <span class="hljs-keyword">require</span> railsware/mailtrap-php guzzlehttp/guzzle php-http/guzzle7-adapter
</code></pre>
<p>Once that’s done, copy the source code from GitHub and tweak it with the HTML content you want to use. With this SDK, you can set the reply-to address, add Cc or Bcc recipients, send HTML and plain text emails, embed images, set custom headers, and indicate the category (the latter is useful for analytics). </p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">Config</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">EmailHeader</span>\<span class="hljs-title">CategoryHeader</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">EmailHeader</span>\<span class="hljs-title">CustomVariableHeader</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">Helper</span>\<span class="hljs-title">ResponseHelper</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">MailtrapClient</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Address</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Email</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Header</span>\<span class="hljs-title">UnstructuredHeader</span>;

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/vendor/autoload.php'</span>;

<span class="hljs-comment">// your API token from here https://mailtrap.io/api-tokens</span>
$apiKey = getenv(<span class="hljs-string">'MAILTRAP_API_KEY'</span>);
$mailtrap = <span class="hljs-keyword">new</span> MailtrapClient(<span class="hljs-keyword">new</span> Config($apiKey));

$email = (<span class="hljs-keyword">new</span> Email())
    -&gt;from(<span class="hljs-keyword">new</span> Address(<span class="hljs-string">'example@your-domain-here.com'</span>, <span class="hljs-string">'Mailtrap Test'</span>))
    -&gt;replyTo(<span class="hljs-keyword">new</span> Address(<span class="hljs-string">'reply@your-domain-here.com'</span>))
    -&gt;to(<span class="hljs-keyword">new</span> Address(<span class="hljs-string">'email@example.com'</span>, <span class="hljs-string">'Jon'</span>))
    -&gt;priority(Email::PRIORITY_HIGH)
    -&gt;cc(<span class="hljs-string">'mailtrapqa@example.com'</span>)
    -&gt;addCc(<span class="hljs-string">'staging@example.com'</span>)
    -&gt;bcc(<span class="hljs-string">'mailtrapdev@example.com'</span>)
    -&gt;subject(<span class="hljs-string">'Best practices of building HTML emails'</span>)
    -&gt;text(<span class="hljs-string">'Hey! Learn the best practices of building HTML emails and play with ready-to-go templates. Mailtrap'</span>s Guide on How to Build HTML Email is live on our blog<span class="hljs-string">')
    -&gt;html(
        '</span>&lt;html&gt;
        &lt;body&gt;
        &lt;p&gt;&lt;br&gt;Hey&lt;/br&gt;
        Learn the best practices of building HTML emails <span class="hljs-keyword">and</span> play with ready-to-go templates.&lt;/p&gt;
        &lt;p&gt;&lt;a href=<span class="hljs-string">"https://mailtrap.io/blog/build-html-email/"</span>&gt;Mailtrap<span class="hljs-string">'s Guide on How to Build HTML Email&lt;/a&gt; is live on our blog&lt;/p&gt;
        &lt;img src="cid:logo"&gt;
        &lt;/body&gt;
    &lt;/html&gt;'</span>
    )
    -&gt;embed(fopen(<span class="hljs-string">'https://mailtrap.io/wp-content/uploads/2021/04/mailtrap-new-logo.svg'</span>, <span class="hljs-string">'r'</span>), <span class="hljs-string">'logo'</span>, <span class="hljs-string">'image/svg+xml'</span>)
    ;

    <span class="hljs-comment">// Headers</span>
    $email-&gt;getHeaders()
    -&gt;addTextHeader(<span class="hljs-string">'X-Message-Source'</span>, <span class="hljs-string">'domain.com'</span>)
    -&gt;add(<span class="hljs-keyword">new</span> UnstructuredHeader(<span class="hljs-string">'X-Mailer'</span>, <span class="hljs-string">'Mailtrap PHP Client'</span>)) <span class="hljs-comment">// the same as addTextHeader</span>
    ;

    <span class="hljs-comment">// Custom Variables</span>
    $email-&gt;getHeaders()
    -&gt;add(<span class="hljs-keyword">new</span> CustomVariableHeader(<span class="hljs-string">'user_id'</span>, <span class="hljs-string">'45982'</span>))
    -&gt;add(<span class="hljs-keyword">new</span> CustomVariableHeader(<span class="hljs-string">'batch_id'</span>, <span class="hljs-string">'PSJ-12'</span>))
    ;

    <span class="hljs-comment">// Category (should be only one)</span>
    $email-&gt;getHeaders()
    -&gt;add(<span class="hljs-keyword">new</span> CategoryHeader(<span class="hljs-string">'Integration Test'</span>))
    ;

<span class="hljs-keyword">try</span> {
    $response = $mailtrap-&gt;sending()-&gt;emails()-&gt;send($email); <span class="hljs-comment">// Email sending API (real)</span>

    var_dump(ResponseHelper::toArray($response)); <span class="hljs-comment">// body (array)</span>
} <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Exception</span> $e) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Caught exception: '</span>,  $e-&gt;getMessage(), <span class="hljs-string">"\n"</span>;
}
</code></pre>
<p><strong>Pro Tip</strong>: Before sending an email to recipients, send an email to <a target="_blank" href="https://mailtrap.io/email-sandbox/">Mailtrap Email Testing</a> virtual inbox using the PHP SDK to inspect and debug your HTML emails. My team and I always use this option to ensure the integration works and the template renders correctly. I’ll talk about testing in more detail <a target="_blank" href="https://mailtrap.io/?p=25523&amp;preview=true#Test-your-HTML-emails-in-PHP-before-sending-why-and-how">in this section</a>. </p>
<h3 id="heading-send-html-emails-with-templates"><strong>Send HTML emails with templates</strong></h3>
<p>If you prefer to use an HTML template, you should first create it in Mailtrap and then call it with the SDK. Here’s how: </p>
<ol>
<li>In your Mailtrap account, go to <em>Email Sending</em> → <em>Email Templates</em>, and click the C<em>reate New Template</em> button.  </li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/03/image-2.png" alt="Creating a template in Mailtrap Email Sending " /></p>
<ol start="2">
<li>Select the domain you want to create the template for, choose the ready-made template or select <em>Start from scratch</em>, and click <em>Create Template</em>. </li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/03/image-7.png" alt="Choosing a desired template format in Mailtrap Email Sending " /></p>
<ol start="3">
<li>From the <em>Details</em> tab, specify the <em>Email Category</em> and add the template name. Then, go to <em>Code Editor</em> and modify the template or paste your own. </li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/03/image-9.png" alt="Welcome email template in Mailtrap Email Sending " /></p>
<ol start="4">
<li><p>Remember that Mailtrap Email Templates operate on the handlebars engine and support variables. This means that you can add, for example, {{user_name}} to your template and pass “John” as the “user_name” value via API. </p>
</li>
<li><p>Once the template is ready, go to the <em>Integrations</em> tab and select PHP from the dropdown menu. You’ll see a sample configuration that uses PHP SDK and already contains your credentials. </p>
</li>
</ol>
<p>For a Welcome Email template, this is what the code will look like: </p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">Config</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">Helper</span>\<span class="hljs-title">ResponseHelper</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">MailtrapClient</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Address</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Email</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">EmailHeader</span>\<span class="hljs-title">Template</span>\<span class="hljs-title">TemplateUuidHeader</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">EmailHeader</span>\<span class="hljs-title">Template</span>\<span class="hljs-title">TemplateVariableHeader</span>;

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/vendor/autoload.php'</span>;

$apiKey = <span class="hljs-string">'your_mailtrap_api_key'</span>;
$mailtrap = <span class="hljs-keyword">new</span> MailtrapClient(<span class="hljs-keyword">new</span> Config($apiKey));

$email = (<span class="hljs-keyword">new</span> Email())
    -&gt;from(<span class="hljs-keyword">new</span> Address(<span class="hljs-string">'sender@your-domain.com'</span>, <span class="hljs-string">'Mailtrap Team'</span>))
    -&gt;to(<span class="hljs-keyword">new</span> Address(<span class="hljs-string">"recipient@example.com"</span>))
;

$email-&gt;getHeaders()
    -&gt;add(<span class="hljs-keyword">new</span> TemplateUuidHeader(<span class="hljs-string">'your_template_Uuid'</span>))
    -&gt;add(<span class="hljs-keyword">new</span> TemplateVariableHeader(<span class="hljs-string">'user_name'</span>, <span class="hljs-string">'John Doe'</span>))
    -&gt;add(<span class="hljs-keyword">new</span> TemplateVariableHeader(<span class="hljs-string">'next_step_link'</span>, <span class="hljs-string">'https://mailtrap.io/'</span><span class="hljs-string">'))
    -&gt;add(new TemplateVariableHeader('</span>get_started_link<span class="hljs-string">', '</span>https:<span class="hljs-comment">//mailtrap.io/'))</span>
    -&gt;add(<span class="hljs-keyword">new</span> TemplateVariableHeader(<span class="hljs-string">'onboarding_video_link'</span>, <span class="hljs-string">'some_video_link'</span>))
;

$response = $mailtrap-&gt;sending()-&gt;emails()-&gt;send($email);

var_dump(ResponseHelper::toArray($response));
</code></pre>
<p>Of course, before sending the template to recipients, you can preview it and send a test email to yourself. </p>
<p><a target="_blank" href="https://mailtrap.io/register/signup"><strong>Start Sending with Mailtrap</strong></a></p>
<h2 id="heading-send-html-emails-using-symfonymailer"><strong>Send HTML emails using SymfonyMailer</strong></h2>
<p>The last sending method I’ll cover in this article is <a target="_blank" href="https://github.com/symfony/mailer">SymfonyMailer</a>. It’s the mailer component of the Symfony framework (a popular PHP framework for web development). SymfonyMailer allows you to:</p>
<ul>
<li><p>Send emails in HTML format;</p>
</li>
<li><p>Integrate your project with third-party sending providers;</p>
</li>
<li><p>Use Twig templates;</p>
</li>
<li><p>Use CSS inliner;</p>
</li>
<li><p>Add attachments. </p>
</li>
</ul>
<h3 id="heading-send-a-basic-html-message-1"><strong>Send a basic HTML message</strong></h3>
<p>Before we start building the message body, we need to install SymfonyMailer. Run the following command: </p>
<pre><code class="lang-php">$ composer <span class="hljs-keyword">require</span> symfony/mailer
</code></pre>
<p>The next step is configuring the transport, which is the method that will be used for delivering your emails. Symfony offers three built-in transports:</p>
<ul>
<li><p>SMTP that can be configured with any third-party SMTP server; </p>
</li>
<li><p>Sendmail that uses local sendmail binary;</p>
</li>
<li><p>And Native that uses the sendmail binary and the options configured in the <code>sendmail_path</code>of the <em>php.ini</em>. If the <code>sendmail_path</code> isn’t configured, the mailer will fall back to SMTP and <code>smtp_port</code> <em>php.ini</em> settings (applies to Windows hosts). </p>
</li>
</ul>
<p>And there are multiple third-party transports for various email service providers. </p>
<p>I’ll use the SMTP transport with Mailtrap Email Sending SMTP server. Once again, we’ll need to grab the credentials from the Mailtrap account and configure MAILER_DSN in the <em>.env</em> file. </p>
<pre><code class="lang-php">MAILER_DSN=smtp:<span class="hljs-comment">//api:yourpassword@live.smtp.mailtrap.io:587/?encryption=ssl&amp;auth_mode=login</span>
</code></pre>
<p>Once the transport is configured, we can start building the message. </p>
<p>First, configure the necessary namespaces like this: </p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Bundle</span>\<span class="hljs-title">FrameworkBundle</span>\<span class="hljs-title">Controller</span>\<span class="hljs-title">AbstractController</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mailer</span>\<span class="hljs-title">MailerInterface</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Address</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Email</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Routing</span>\<span class="hljs-title">Annotation</span>\<span class="hljs-title">Route</span>;
</code></pre>
<p>Then, use the <code>MailerController</code> class that extends to <code>AbstractController</code>. Specify the route, which will call the index method when you make a request to it. </p>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MailerController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractController</span>
</span>{
    <span class="hljs-comment">#[Route('/mailer', name: 'app_mailer')]</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params">MailerInterface $mailer</span>): <span class="hljs-title">Response</span>
    </span>{
</code></pre>
<p>Then, I’ll build the message with the Email object. I won’t use a template this time, so I’ll specify an HTML body. Let’s take a look at the complete code for the email: </p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Bundle</span>\<span class="hljs-title">FrameworkBundle</span>\<span class="hljs-title">Controller</span>\<span class="hljs-title">AbstractController</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mailer</span>\<span class="hljs-title">MailerInterface</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Address</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Email</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Routing</span>\<span class="hljs-title">Annotation</span>\<span class="hljs-title">Route</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MailerController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractController</span>
</span>{
    <span class="hljs-comment">#[Route('/mailer', name: 'app_mailer')]</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params">MailerInterface $mailer</span>): <span class="hljs-title">Response</span>
    </span>{
        $email = (<span class="hljs-keyword">new</span> Email())
            -&gt;from(<span class="hljs-string">'mailtrap@example.com'</span>)
            -&gt;to(<span class="hljs-keyword">new</span> Address(<span class="hljs-string">'newuser@example.com'</span>))
            -&gt;cc(<span class="hljs-string">'mailtrapqa@example.com'</span>)
            -&gt;addCc(<span class="hljs-string">'staging@example.com'</span>)
            -&gt;bcc(<span class="hljs-string">'mailtrapdev@example.com'</span>)
            -&gt;replyTo(<span class="hljs-string">'mailtrap@example.com'</span>)
            -&gt;subject(<span class="hljs-string">'Here is the subject'</span>)
            -&gt;text(<span class="hljs-string">'Hey! Learn the best practices of building HTML emails and play with ready-to-go templates. Mailtrap'</span>s Guide on How to Build HTML Email is live on our blog<span class="hljs-string">')
            -&gt;html('</span>&lt;html&gt;
                        &lt;body&gt;
                            &lt;p&gt;Hey!&lt;br&gt;
                            Learn the best practices of building HTML emails <span class="hljs-keyword">and</span> play with ready-to-go templates.&lt;/p&gt;
                            &lt;p&gt;&lt;a href=<span class="hljs-string">"https://blog.mailtrap.io/build-html-email/"</span>&gt;Mailtrap<span class="hljs-string">'s Guide on How to Build HTML Email&lt;/a&gt; is live on our blog&lt;/p&gt;
                        &lt;/body&gt;
                    &lt;/html&gt;'</span>);

        $mailer-&gt;send($email);

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(
            content: <span class="hljs-string">'Email was sent'</span>
        );
    }
}
</code></pre>
<h3 id="heading-send-an-html-mail-with-an-embedded-image"><strong>Send an HTML mail with an embedded image</strong></h3>
<p>In terms of embedding, SymfonyMailer supports three methods: embedding an image from a PHP resource, embedding an image hosted locally or on a server, and embedding it with CID attachments. Here’s what each of these would look like: </p>
<pre><code class="lang-php">$email = (<span class="hljs-keyword">new</span> Email())
    <span class="hljs-comment">// ...</span>
    <span class="hljs-comment">//image from a PHP resource, for example, GD</span>
    -&gt;embed(fopen(<span class="hljs-string">'/path/to/newlogo.png'</span>, <span class="hljs-string">'r'</span>), <span class="hljs-string">'logo'</span>)
    <span class="hljs-comment">//image hosted locally or on some external resource</span>
    -&gt;embedFromPath(<span class="hljs-string">'/path/to/newcover.png'</span>, <span class="hljs-string">'new-cover-image'</span>)
    <span class="hljs-comment">// CID attachment</span>
    -&gt;html(<span class="hljs-string">'&lt;img src="cid:logo"&gt; ... &lt;img src="cid:new-cover-image"&gt; ...'</span>);
</code></pre>
<h3 id="heading-send-an-email-with-html-email-template"><strong>Send an email with HTML email template</strong></h3>
<p>As I mentioned above, SymfonyMailer supports Twig templates. These are integrated with the MIME component. Twig templates have several useful features, including CSS inlining and direct integration with HTML/CSS frameworks. </p>
<p>First, create a template and save it as a <em>.twig</em> file. Detailed instructions on creating Twig templates are available <a target="_blank" href="https://symfony.com/doc/current/mailer.html#twig-html-css">here</a>. </p>
<p>Then, use the <code>TemplatedEmail</code> class, which extends the <code>Email</code> class to add new methods for Twig templates. Instead of the <code>-&gt;html</code>and HTML body, add <code>-&gt;htmlTemplate('path/experiment.html.twig')</code>. Of course, you should use an actual path to the template. </p>
<p>Remember that Mailtrap PHP SDK works with both Symfony and Laravel, which means you could use Mailtrap Email Templates instead of Twig. </p>
<h3 id="heading-send-html-emails-to-multiple-recipients-1"><strong>Send HTML emails to multiple recipients</strong></h3>
<p>Sending emails to multiple recipients is pretty straightforward as well. You can either make multiple <code>to</code> calls or create an array of <code>Address</code> objects. I went with the latter and modified the previous code snippet like this: </p>
<pre><code class="lang-php"><span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Bundle</span>\<span class="hljs-title">FrameworkBundle</span>\<span class="hljs-title">Controller</span>\<span class="hljs-title">AbstractController</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">HttpFoundation</span>\<span class="hljs-title">Response</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mailer</span>\<span class="hljs-title">MailerInterface</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Address</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Email</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Routing</span>\<span class="hljs-title">Annotation</span>\<span class="hljs-title">Route</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MailerController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractController</span>
</span>{
    <span class="hljs-comment">#[Route('/mailer', name: 'app_mailer')]</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span>(<span class="hljs-params">MailerInterface $mailer</span>): <span class="hljs-title">Response</span>
    </span>{
        <span class="hljs-comment">// Define the recipients</span>
        $recipients = [
            <span class="hljs-keyword">new</span> Address(<span class="hljs-string">'firstuser@example.com'</span>, <span class="hljs-string">'First User'</span>),
            <span class="hljs-keyword">new</span> Address(<span class="hljs-string">'seconduser@example.com'</span>, <span class="hljs-string">'Second User'</span>),
            <span class="hljs-comment">// ... Add more recipients as needed</span>
        ];

        $email = (<span class="hljs-keyword">new</span> Email())
            -&gt;from(<span class="hljs-string">'mailtrap@example.com'</span>)
            <span class="hljs-comment">// Use the array of recipients for the 'To' field</span>
            -&gt;to(...$recipients) <span class="hljs-comment">// The '...' is the spread operator, which unpacks the array elements</span>
            -&gt;cc(<span class="hljs-string">'mailtrapqa@example.com'</span>)
            -&gt;addCc(<span class="hljs-string">'staging@example.com'</span>)
            -&gt;bcc(<span class="hljs-string">'mailtrapdev@example.com'</span>)
            -&gt;replyTo(<span class="hljs-string">'mailtrap@example.com'</span>)
            -&gt;subject(<span class="hljs-string">'Here is the subject'</span>)
            -&gt;text(<span class="hljs-string">'Hey! Learn the best practices of building HTML emails and play with ready-to-go templates. Mailtrap'</span>s Guide on How to Build HTML Email is live on our blog<span class="hljs-string">')
            -&gt;html('</span>&lt;html&gt;
                        &lt;body&gt;
                            &lt;p&gt;Hey!&lt;br&gt;
                            Learn the best practices of building HTML emails <span class="hljs-keyword">and</span> play with ready-to-go templates.&lt;/p&gt;
                            &lt;p&gt;&lt;a href=<span class="hljs-string">"https://blog.mailtrap.io/build-html-email/"</span>&gt;Mailtrap<span class="hljs-string">'s Guide on How to Build HTML Email&lt;/a&gt; is live on our blog&lt;/p&gt;
                        &lt;/body&gt;
                    &lt;/html&gt;'</span>);

        $mailer-&gt;send($email);

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(
            <span class="hljs-string">'Email was sent'</span>
        );
    }
}
</code></pre>
<h3 id="heading-send-an-html-email-with-attachments-1"><strong>Send an HTML email with attachments</strong></h3>
<p>Finally, let’s see how you can send emails with attachments. This process is similar to embedding images. You have three options: </p>
<ul>
<li><p>Use <code>attachFromPath()</code> to include local files; </p>
</li>
<li><p>Use <code>attachFromPath()</code> to include files from an external link; </p>
</li>
<li><p>And use <code>attach()</code> to add files from a PHP resource. </p>
</li>
</ul>
<p>Here are the examples for each option: </p>
<pre><code class="lang-php">$email = (<span class="hljs-keyword">new</span> Email())
    <span class="hljs-comment">// ...</span>
<span class="hljs-comment">// local file</span>
    -&gt;attachFromPath(<span class="hljs-string">'/path/to/yourconfirmation.pdf'</span>)
<span class="hljs-comment">// external URL - make sure that allow_url_fopen is enabled in your PHP installation</span>
-&gt;attachFromPath(<span class="hljs-string">'http://mailtrap.io/path/to/yourconfirmation'</span>, <span class="hljs-string">'Your Confirmation'</span>, <span class="hljs-string">'application/msword'</span>)
<span class="hljs-comment">// PHP resource</span>
  -&gt;attach(fopen(<span class="hljs-string">'/path/to/yourconfirmation.pdf'</span>, <span class="hljs-string">'r'</span>));
</code></pre>
<h2 id="heading-send-html-emails-from-an-html-form-with-php-as-a-backend"><strong>Send HTML emails from an HTML form with PHP as a backend</strong></h2>
<p>If you want your PHP contact form to automatically send HTML email, you need to configure server-side script (PHP), JavaScript validation (with validate.js), and an HTML form itself.</p>
<p>For detailed instructions on building an HTML form and sending emails from it, <a target="_blank" href="https://mailtrap.io/blog/html-form-send-email/">read this article</a>. Here, I’ll just leave you a script that collects contact form data, validates it, and sends an HTML email to the indicated email address. </p>
<p>Since I wanted the contact form to send an HTML email instead of a text message, I set <code>isHTML</code> to true and added HTML content. </p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">use</span> <span class="hljs-title">PHPMailer</span>\<span class="hljs-title">PHPMailer</span>\<span class="hljs-title">PHPMailer</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">PHPMailer</span>\<span class="hljs-title">PHPMailer</span>\<span class="hljs-title">Exception</span>;

<span class="hljs-keyword">require</span> <span class="hljs-string">'vendor/autoload.php'</span>;

$errors = [];
$errorMessage = <span class="hljs-string">''</span>;
$successMessage = <span class="hljs-string">''</span>;
$siteKey = <span class="hljs-string">'YOUR_RECAPTCHA_SITE_KEY'</span>;
$secret = <span class="hljs-string">'YOUR_RECAPTCHA_SECRET_KEY'</span>;

<span class="hljs-keyword">if</span> ($_SERVER[<span class="hljs-string">'REQUEST_METHOD'</span>] === <span class="hljs-string">'POST'</span>) {
    $name = sanitizeInput ($_POST[<span class="hljs-string">'name'</span>]);
    $email = sanitizeInput ($_POST[<span class="hljs-string">'email'</span>]);
    $message = sanitizeInput ($_POST [<span class="hljs-string">'message'</span>]);
    $recaptchaResponse = sanitizeInput ($_POST[<span class="hljs-string">'g-recaptcha-response'</span>]);

    $recaptchaUrl = <span class="hljs-string">"https://www.google.com/recaptcha/api/siteverify?secret=<span class="hljs-subst">{$secret]&amp;response={$recaptchaResponse]";
    $verify = json_decode(file_get_contents($recaptchaUrl));

    if (!$verify-&gt;success) {
        $errors [ ] = 'Recaptcha failed';
    }</span>
    if (empty (<span class="hljs-subst">$name</span>)) {
        <span class="hljs-subst">$errors</span> [ ] = 'Name is empty';
    }
    if (empty (<span class="hljs-subst">$email</span>)) {
        <span class="hljs-subst">$errors</span> [ ] = 'Email is empty';
    } else if (!filter_var(<span class="hljs-subst">$email</span>, filter: FILTER_VALIDATE_EMAIL)) {
        <span class="hljs-subst">$errors</span> [ ] = 'Email is invalid';
    }
    if (empty (<span class="hljs-subst">$message</span>)) {
        <span class="hljs-subst">$errors</span> [ ] = 'Message is empty';
}

    if (!empty (<span class="hljs-subst">$errors</span>)) {
        <span class="hljs-subst">$allErrors</span> = join ( separator: '&lt;br/&gt;', <span class="hljs-subst">$errors</span>);
        <span class="hljs-subst">$errorMessage</span> = "</span>&lt;p style=<span class="hljs-string">'color: red; '</span>&gt;{$allErrors}&lt;/p&gt;<span class="hljs-string">";
    } else {
        <span class="hljs-subst">$toEmail</span> = 'myemail@example.com';
        <span class="hljs-subst">$emailSubject</span> = 'New email from your contact form';

        // Create a new PHPMailer instance
      <span class="hljs-subst">$mail</span> = new PHPMailer (exceptions: true);
      try {
            // Configure the PHPMailer instance
            <span class="hljs-subst">$mail</span>-&gt;isSMTP();
            <span class="hljs-subst">$mail</span>-&gt;Host = 'live.smtp.mailtrap.io';
            <span class="hljs-subst">$mail</span>-&gt;SMTPAuth = true;
            <span class="hljs-subst">$mail</span>-&gt;Username = 'api';
            <span class="hljs-subst">$mail</span>-&gt;Password = 'your_smtp_password';
            <span class="hljs-subst">$mail</span>-&gt;SMTPSecure = 'tls';
            <span class="hljs-subst">$mail</span>-&gt;Port = 587;

            // Set the sender, recipient, subject, and body of the message
            <span class="hljs-subst">$mail</span>-&gt;setFrom(<span class="hljs-subst">$email</span>);
            <span class="hljs-subst">$mail</span>-&gt;addAddress(<span class="hljs-subst">$toEmail</span>);
            <span class="hljs-subst">$mail</span>-&gt;Subject = <span class="hljs-subst">$emailSubject</span>;
            <span class="hljs-subst">$mail</span>-&gt;isHTML(true);
            <span class="hljs-subst">$mail</span>-&gt;Body = "</span>&lt;p&gt;Name: {$name]&lt;/p&gt;&lt;p&gt;Email: {$email]&lt;/p&gt;&lt;p&gt;Message: {$message]&lt;/p&gt;;

            <span class="hljs-comment">// Send the message</span>
            $mail-&gt;send () ;
            $successMessage = <span class="hljs-string">"&lt;p style='color: green; '&gt;Thank you for contacting us :)&lt;/p&gt;"</span>;
      } <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Exception</span> $e) {
            $errorMessage = <span class="hljs-string">"&lt;p style='color: red; '&gt;Oops, something went wrong. Please try again later&lt;/p&gt;"</span>;
      }
    }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sanitizeInput</span>(<span class="hljs-params">$input</span>) </span>{
    $input = trim($input);
    $input = stripslashes($input);
    $input = htmlspecialchars($input, ENT_QUOTES, <span class="hljs-string">'UTF-8'</span>);
    <span class="hljs-keyword">return</span> $input;
}
<span class="hljs-meta">?&gt;</span>

&lt;html&gt;
&lt;body&gt;
&lt;script src=<span class="hljs-string">"https://www.google.com/recaptcha/api.js"</span> async defer&gt;&lt;/script&gt;
&lt;form action=<span class="hljs-string">"/"</span> method=<span class="hljs-string">"post"</span> id=<span class="hljs-string">"contact-form"</span>&gt;
    &lt;h2&gt;Contact us&lt;/h2&gt;
    <span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">echo</span> (!<span class="hljs-keyword">empty</span>($errorMessage) ? $errorMessage : <span class="hljs-string">''</span>); <span class="hljs-meta">?&gt;</span>
    <span class="hljs-meta">&lt;?php</span> <span class="hljs-keyword">echo</span> (!<span class="hljs-keyword">empty</span>($successMessage) ? $successMessage : <span class="hljs-string">''</span>); <span class="hljs-meta">?&gt;</span>
    &lt;p&gt;
        &lt;label&gt;First Name:&lt;/label&gt;
        &lt;input name=<span class="hljs-string">"name"</span> type=<span class="hljs-string">"text"</span> required /&gt;
    &lt;/p&gt;
    &lt;p&gt;
        &lt;label&gt;Email Address:&lt;/label&gt;
        &lt;input style=<span class="hljs-string">"..."</span> name=<span class="hljs-string">"email"</span> type=<span class="hljs-string">"email"</span> required /&gt;
    &lt;/p&gt;
    &lt;p&gt;
        &lt;label&gt;Message:&lt;/label&gt;
        &lt;textarea name=<span class="hljs-string">"message"</span> required&gt;&lt;/textarea&gt;
    &lt;/p&gt;
    &lt;p&gt;
        &lt;button <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">g</span>-<span class="hljs-title">recaptcha</span>" <span class="hljs-title">type</span>="<span class="hljs-title">submit</span>" <span class="hljs-title">data</span>-<span class="hljs-title">sitekey</span>="&lt;?<span class="hljs-title">php</span> <span class="hljs-title">echo</span> $<span class="hljs-title">siteKey</span> ?&gt;" <span class="hljs-title">data</span>-<span class="hljs-title">callback</span>="<span class="hljs-title">onRecaptchaSuccess</span>"&gt;
            <span class="hljs-title">Submit</span>
        &lt;/<span class="hljs-title">button</span>&gt;
    &lt;/<span class="hljs-title">p</span>&gt;
&lt;/<span class="hljs-title">form</span>&gt;

&lt;<span class="hljs-title">script</span>&gt;
    <span class="hljs-title">function</span> <span class="hljs-title">onRecaptchaSuccess</span>() </span>{
        document.getElementById(<span class="hljs-string">'contact-form'</span>).submit();
    }
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h2 id="heading-test-your-html-emails-in-php-before-sending-why-and-how"><strong>Test your HTML emails in PHP before sending: why and how</strong></h2>
<p>Have you spent hours building an HTML email and configuring the code only for it to look like an upside-down kid’s drawing? I surely have, more than once, if I dare to admit. This is especially problematic when sending HTML emails with embedded images or attachments. </p>
<p>Images may get blocked, attachments may not attach, or your emails might end up in the dreaded spam folder. To avoid all that, it’s best practice to test your emails before sending them to recipients. I’d go as far as saying that it’s mandatory if you don’t want to lose customers.  </p>
<p>You can easily test your emails with a dedicated testing tool such as <a target="_blank" href="https://mailtrap.io/email-sandbox/">Mailtrap Email Testing</a>. Along with Email Sending, Email Testing is part of the <a target="_blank" href="https://mailtrap.io/">Mailtrap Email Delivery Platform</a>. </p>
<p>Email Testing is an Email Sandbox that captures all the SMTP traffic and allows you to inspect and debug emails in staging without spamming recipients. You can integrate it using the SMTP credentials or use official SDKs. </p>
<h3 id="heading-test-emails-with-mailtrap-email-testing-smtp"><strong>Test emails with Mailtrap Email Testing SMTP</strong></h3>
<p>To integrate Email Testing using an SMTP server, follow these steps: </p>
<ol>
<li><p>Go to Email Testing and click on the desired inbox. </p>
</li>
<li><p>Click <em>Show Credentials</em>. </p>
</li>
<li><p>Copy the credentials under SMTP and paste them into your PHPMailer script or SymfonyMailer transport configuration. </p>
</li>
<li><p>Alternatively, choose the package or framework you’re using from the dropdown menu under <em>Integrations</em> and copy a sample configuration with your credentials. </p>
</li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/03/image-8.png" alt /></p>
<p>For PHPMailer, Email Testing configuration will look like this: </p>
<pre><code class="lang-php">$phpmailer = <span class="hljs-keyword">new</span> PHPMailer();
$phpmailer-&gt;isSMTP();
$phpmailer-&gt;Host = <span class="hljs-string">'sandbox.smtp.mailtrap.io'</span>;
$phpmailer-&gt;SMTPAuth = <span class="hljs-literal">true</span>;
$phpmailer-&gt;Port = <span class="hljs-number">2525</span>;
$phpmailer-&gt;Username = <span class="hljs-string">'your_username'</span>;
$phpmailer-&gt;Password = <span class="hljs-string">'your_password'</span>;
</code></pre>
<p>In SymfonyMailer, you should set your MAILER_DSN value to the following: </p>
<pre><code class="lang-php">MAILER_DSN=smtp:<span class="hljs-comment">//yourusername:yourpassword@sandbox.smtp.mailtrap.io:2525</span>
</code></pre>
<h3 id="heading-test-emails-with-mailtrap-email-testing-api"><strong>Test emails with Mailtrap Email Testing API</strong></h3>
<p>As mentioned above, you can use Mailtrap official PHP client to send emails to the Email Testing virtual inbox. For that, you’ll need to modify the <em>try catch</em> block, grab an API token for the inbox, and copy the inbox ID. </p>
<ol>
<li>Create an API token as we did for Email Sending. Under Email Testing, choose the desired inbox. </li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/03/image-5.png" alt="Creating an API token for the Email Testing inbox " /></p>
<ol start="2">
<li>Go to Email Testing and open the desired inbox. In the URL, you’ll find the seven-digit inbox ID. </li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/03/image-6.png" alt="Copying Email Testing inbox ID" /></p>
<p>Add your API token to the <em>.env</em> file and the inbox ID to the following script: </p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">Config</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">EmailHeader</span>\<span class="hljs-title">CategoryHeader</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">EmailHeader</span>\<span class="hljs-title">CustomVariableHeader</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">Helper</span>\<span class="hljs-title">ResponseHelper</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Mailtrap</span>\<span class="hljs-title">MailtrapClient</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Address</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Email</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">Symfony</span>\<span class="hljs-title">Component</span>\<span class="hljs-title">Mime</span>\<span class="hljs-title">Header</span>\<span class="hljs-title">UnstructuredHeader</span>;

<span class="hljs-keyword">require</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/vendor/autoload.php'</span>;

<span class="hljs-comment">// your API token from here https://mailtrap.io/api-tokens</span>
$apiKey = getenv(<span class="hljs-string">'MAILTRAP_API_KEY'</span>);
$mailtrap = <span class="hljs-keyword">new</span> MailtrapClient(<span class="hljs-keyword">new</span> Config($apiKey));

$email = (<span class="hljs-keyword">new</span> Email())
    -&gt;from(<span class="hljs-keyword">new</span> Address(<span class="hljs-string">'example@your-domain-here.com'</span>, <span class="hljs-string">'Mailtrap Test'</span>))
    -&gt;replyTo(<span class="hljs-keyword">new</span> Address(<span class="hljs-string">'reply@your-domain-here.com'</span>))
    -&gt;to(<span class="hljs-keyword">new</span> Address(<span class="hljs-string">'email@example.com'</span>, <span class="hljs-string">'Jon'</span>))
    -&gt;priority(Email::PRIORITY_HIGH)
    -&gt;cc(<span class="hljs-string">'mailtrapqa@example.com'</span>)
    -&gt;addCc(<span class="hljs-string">'staging@example.com'</span>)
    -&gt;bcc(<span class="hljs-string">'mailtrapdev@example.com'</span>)
    -&gt;subject(<span class="hljs-string">'Best practices of building HTML emails'</span>)
    -&gt;text(<span class="hljs-string">'Hey! Learn the best practices of building HTML emails and play with ready-to-go templates. Mailtrap'</span>s Guide on How to Build HTML Email is live on our blog<span class="hljs-string">')
    -&gt;html(
        '</span>&lt;html&gt;
        &lt;body&gt;
        &lt;p&gt;&lt;br&gt;Hey&lt;/br&gt;
        Learn the best practices of building HTML emails <span class="hljs-keyword">and</span> play with ready-to-go templates.&lt;/p&gt;
        &lt;p&gt;&lt;a href=<span class="hljs-string">"https://mailtrap.io/blog/build-html-email/"</span>&gt;Mailtrap<span class="hljs-string">'s Guide on How to Build HTML Email&lt;/a&gt; is live on our blog&lt;/p&gt;
        &lt;img src="cid:logo"&gt;
        &lt;/body&gt;
    &lt;/html&gt;'</span>
    )
    -&gt;embed(fopen(<span class="hljs-string">'https://mailtrap.io/wp-content/uploads/2021/04/mailtrap-new-logo.svg'</span>, <span class="hljs-string">'r'</span>), <span class="hljs-string">'logo'</span>, <span class="hljs-string">'image/svg+xml'</span>)
    ;

    <span class="hljs-comment">// Headers</span>
    $email-&gt;getHeaders()
    -&gt;addTextHeader(<span class="hljs-string">'X-Message-Source'</span>, <span class="hljs-string">'domain.com'</span>)
    -&gt;add(<span class="hljs-keyword">new</span> UnstructuredHeader(<span class="hljs-string">'X-Mailer'</span>, <span class="hljs-string">'Mailtrap PHP Client'</span>)) <span class="hljs-comment">// the same as addTextHeader</span>
    ;

    <span class="hljs-comment">// Custom Variables</span>
    $email-&gt;getHeaders()
    -&gt;add(<span class="hljs-keyword">new</span> CustomVariableHeader(<span class="hljs-string">'user_id'</span>, <span class="hljs-string">'45982'</span>))
    -&gt;add(<span class="hljs-keyword">new</span> CustomVariableHeader(<span class="hljs-string">'batch_id'</span>, <span class="hljs-string">'PSJ-12'</span>))
    ;

    <span class="hljs-comment">// Category (should be only one)</span>
    $email-&gt;getHeaders()
    -&gt;add(<span class="hljs-keyword">new</span> CategoryHeader(<span class="hljs-string">'Integration Test'</span>))
    ;

<span class="hljs-keyword">try</span> {
    $response = $mailtrap-&gt;sandbox()-&gt;emails()-&gt;send($email, <span class="hljs-number">1000001</span>); <span class="hljs-comment">// Required second param -&gt; inbox_id</span>

    var_dump(ResponseHelper::toArray($response)); <span class="hljs-comment">// body (array)</span>
} <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Exception</span> $e) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">'Caught exception: '</span>,  $e-&gt;getMessage(), <span class="hljs-string">"\n"</span>;
}
</code></pre>
<p>You can use Mailtrap Email Testing API to automate testing and test multiple sequences. </p>
<p>Once you’ve integrated Email Testing with your PHP project or web application, send your first test email. Then, check its spam score; preview it on mobile, desktop, or tablet devices; check if HTML and text versions are the same; or examine HTML for unsupported elements. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2024/03/image-3.png" alt="Inspecting an email in Mailtrap Email Testing inbox " /></p>
<p>Keep an eye on our <a target="_blank" href="https://www.youtube.com/@mailtrap.">YouTube channel</a>, as our detailed tutorial on testing emails in PHP premiers in April. Until then, give <a target="_blank" href="https://mailtrap.io/blog/test-emails-in-php/">this article</a> a read. </p>
<p><a target="_blank" href="https://mailtrap.io/register/signup%20"><strong>Start Testing with Mailtrap</strong></a></p>
<h2 id="heading-final-words"><strong>Final words</strong></h2>
<p>While I covered popular packages and frameworks for sending HTML emails in PHP, I didn’t mention WordPress as it’s a whole different topic. My dear colleague Veljko wrote an in-depth tutorial on <a target="_blank" href="https://mailtrap.io/blog/wordpress-send-email/">sending emails in WordPress</a> some time ago. There, you’ll find <a target="_blank" href="https://mailtrap.io/blog/wordpress-send-email/#How-to-send-HTML-email">a section about sending HTML emails</a>, which should have you covered for now. </p>
<p>We appreciate the you chose this article to know more about <a target="_blank" href="https://mailtrap.io/blog/php-send-html-email/">HTML email template in PHP</a>. If you want to find more interesting content on related topics, follow Mailtrap blog!</p>
]]></content:encoded></item><item><title><![CDATA[What Is Email Bounce Rate and Why Is It Important?]]></title><description><![CDATA[We all know that spam complaints are a nightmare for anyone sending marketing emails. But so are bounce rates, especially if they are high. 
In today’s blog post, we’ll guide you through the maze of email bounce rates and provide useful tips for keep...]]></description><link>https://ketevanbostoganashvili.hashnode.dev/what-is-email-bounce-rate-and-why-is-it-important</link><guid isPermaLink="true">https://ketevanbostoganashvili.hashnode.dev/what-is-email-bounce-rate-and-why-is-it-important</guid><category><![CDATA[email]]></category><dc:creator><![CDATA[Ketevan Bostoganashvili]]></dc:creator><pubDate>Wed, 31 Jan 2024 09:53:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706694687616/7cb14fed-b231-405b-9879-5a2ee412e752.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We all know that spam complaints are a nightmare for anyone sending marketing emails. But so are bounce rates, especially if they are high. </p>
<p>In today’s blog post, we’ll guide you through the maze of email bounce rates and provide useful tips for keeping them in check. </p>
<h2 id="heading-what-is-email-bounce-rate"><strong>What is email bounce rate?</strong></h2>
<p>An email bounce rate is the percentage of emails that couldn’t be delivered from the total number of sent emails. <a target="_blank" href="https://mailtrap.io/blog/what-is-email-bounce/">Email bounce</a> itself is a delivery failure, either temporary or permanent. </p>
<p>Let’s say you want to surprise a friend you haven’t seen for ages. You search for their address in your address book and head to their apartment. When you arrive, you find out that they don’t live there anymore. You go back home feeling frustrated. </p>
<p>Well, that’s what happens to your emails when they can’t reach your recipient’s email address. Sad bounced emails return back to you. </p>
<p>Generally, there are two types of email bounces: </p>
<ul>
<li><strong>Soft bounce</strong>: a temporary issue with delivery. It usually means that there’s a problem with the recipient’s email server or mailbox. Typical causes include full inbox, server overload or error, and <a target="_blank" href="https://mailtrap.io/blog/avoid-spam-filters/">spam filters</a>. Since soft bounces are temporary, mail servers will attempt to deliver emails again later. </li>
</ul>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Soft-bounce-example.png" alt="Soft bounce example from Gmail" /></p>
<ul>
<li><strong>Hard bounce</strong>: a permanent delivery failure. Hard bounces have a greater impact on <a target="_blank" href="https://mailtrap.io/blog/email-sender-reputation/">sender reputation</a> and <a target="_blank" href="https://mailtrap.io/blog/email-deliverability/">email deliverability</a>. Common causes include invalid email addresses, improperly configured (or not configured) email authentication protocols, or blacklisted IPs. Unlike soft bounces, mail servers won’t attempt to resend hard-bounced emails. </li>
</ul>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Hard-Bounce-Example.png" alt="Hard bounce example " /></p>
<p>Read <a target="_blank" href="https://mailtrap.io/blog/soft-vs-hard-bounce/">this blog post</a> for more information on the differences between soft and hard bounces. </p>
<h2 id="heading-how-to-calculate-email-bounce-rate"><strong>How to calculate email bounce rate</strong></h2>
<p>To calculate the email bounce rate, we have to divide the number of bounces by the number of total sent emails. Then we have to multiply the result by 100 to calculate the percentage. So, the formula would be: </p>
<p>Bounce rate = number of bounced emails ÷ number of emails sent × 100</p>
<p>If you send 1,000 emails and 100 of them bounce, the bounce rate would be 10%. </p>
<p>Those who send mass emails will probably have a hard time calculating bounce rates manually. If you’re sending emails from an email service provider (ESP), you should have statistical data for bounced rates. </p>
<p><a target="_blank" href="https://mailtrap.io/email-sending/">Mailtrap Email Sending</a>, for instance, has in-depth actionable analytics with drill-down reports and helicopter-view dashboards. That also includes email bounce rate data. </p>
<p>As an example, let’s see how to check your email bounce rate in Mailtrap. </p>
<ol>
<li><p><a target="_blank" href="https://mailtrap.io/signin">Sign into your account</a>, choose Email Sending, and select ‘Stats’ in the left navigation panel. </p>
</li>
<li><p>There, you’ll see the overall bounce rate for all domains in a selected timeframe. With quick filters, you can see stats for a specific domain. </p>
</li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Mailtrap-Email-Sending-Stats-Dummy-Screenshot.png" alt="Mailtrap Email Sending Statistics with email bounce rate " /></p>
<ol>
<li>To explore trends, scroll down to find a dedicated chart for bounced rates. The critical threshold is 5% – the rates above that will be indicated with a red line. </li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Mailtrap-Email-Sending-Bounce-Rate-Chart.png" alt="Mailtrap Email Sending email bounce rate chart " /></p>
<ol>
<li><p>By clicking bounced emails, you’ll be redirected to Email Logs to find the reasons behind each bounce. </p>
</li>
<li><p>It’s also possible to check bounce rates for different mailbox providers and categories and filter them for a specific domain, time frame, category, or provider. </p>
</li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Mailtrap-Email-Sending-Mailbox-Providers-Stats.png" alt="Mailtrap Email Sending mailbox providers overview" /></p>
<h2 id="heading-email-bounce-rate-benchmark"><strong>Email bounce rate benchmark</strong></h2>
<p>So, what is a good email bounce rate? Based on cross-industry research, <a target="_blank" href="https://www.hostingadvice.com/how-to/average-website-bounce-rate/#:~:text=5.%20An%20Email%20Bounce%20Rate%20of%20Less%20Than%202%25%20Is%20a%20Good%20Goal">anything below 2%</a> is considered to be a normal bounce rate. 2% to 5% is a warning level, while above 5% is critical. </p>
<p>Email providers regularly conduct research to figure out typical email bounce rates. However, those reports are usually based on the campaign data gathered from their users. While the scope of the research makes us believe that the results are objective, we should still take those numbers with a grain of salt. </p>
<p>With that in mind, we decided to provide several examples of reports that have found typical bounce rates. That way, we won’t rely on one source of data. </p>
<h3 id="heading-mailchimp-email-marketing-benchmarks-and-statistics"><strong>Mailchimp email marketing benchmarks and statistics</strong></h3>
<p>In 2019, Mailchimp created a <a target="_blank" href="https://mailchimp.com/en-gb/resources/email-marketing-benchmarks/">comprehensive report</a> on essential <a target="_blank" href="https://mailtrap.io/blog/email-marketing-metrics/">email marketing metrics</a>, such as average <a target="_blank" href="https://mailtrap.io/blog/calculate-email-open-rate/">open rates</a>, click rates, soft and hard bounces, and unsubscribe rates. They analyzed campaigns with at least 1,000 recipients. </p>
<p>Mailchimp found that the Construction industry had the highest average hard bounce rate, amounting to 1.28%. The lowest, on the other hand, was in the Daily Deals/E-Coupons industry with 0.13%. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Mailchimp-Email-Marketing-Benchmarks.png" alt="Mailchimp Email Bounce Rate benchmarks " /></p>
<h3 id="heading-mailerlite-email-marketing-benchmarks"><strong>MailerLite email marketing benchmarks</strong></h3>
<p>MailerLite analyzed <a target="_blank" href="https://www.mailerlite.com/blog/compare-your-email-performance-metrics-industry-benchmarks">2022 data from 40,000 accounts</a>. They included the campaigns that were sent to at least 10 subscribers. As a result, their dataset included around 1M campaigns. </p>
<p>In their report, Publishing companies had the lowest bounce rates (0.2%), while the highest bounce rates (1.32%) were in Architecture and Construction industries. </p>
<h3 id="heading-benchmark-email-report"><strong>Benchmark Email report</strong></h3>
<p><a target="_blank" href="https://www.benchmarkemail.com/email-marketing-benchmarks/">Benchmark email report</a> analyzed a smaller group of users (≈7,470), and their numbers show a slightly different picture.</p>
<p>Advertising/Marketing/PR/Media/Design industries had critically high email bounce rates, averaging 12.27%. In their report, Retail/Consumer Services had the lowest average email bounce rate (6.08%). </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Benchmark-Email-Email-Marketing-Benchmark.png" alt="Benchmark email benchmarks " /></p>
<h3 id="heading-constant-contact-average-industry-rates-for-emails"><strong>Constant Contact average industry rates for emails</strong></h3>
<p>Constant Contact analyzes <a target="_blank" href="https://knowledgebase.constantcontact.com/articles/KnowledgeBase/5409-average-industry-rates?lang=en_US">data from over 200 million emails</a> each month. Their report shows higher bounce rates compared to that of Mailchimp and MailerLite as well: </p>
<ul>
<li><p>Legal Services – 16.27%</p>
</li>
<li><p>Manufacturing and Distribution – 14.73%</p>
</li>
<li><p>Real Estate – 12.72% </p>
</li>
<li><p>Repair and Maintenance – 5.92% </p>
</li>
</ul>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Constant-Contract-Average-Bounce-Rate.png" alt="Constant Conact average email bounce rates " /></p>
<p>We can make three main conclusions from the reports we saw above: </p>
<ul>
<li><p>The source of analysis makes a huge difference in average results;</p>
</li>
<li><p>The acceptable email bounce rate is still below 2% regardless of industry averages;</p>
</li>
<li><p>The bounce rates differ depending on the industry. </p>
</li>
</ul>
<h2 id="heading-what-causes-high-bounce-rates"><strong>What causes high bounce rates?</strong></h2>
<p>High bounce rates for email marketing campaigns and transactional messages can have multiple causes: </p>
<ul>
<li><p><strong>Old or poorly maintained subscriber lists</strong> including <a target="_blank" href="https://salesintel.io/blog/should-you-build-or-buy-your-email-list-for-marketing/">bought email lists</a>, unverified email addresses, and lists full of inactive subscribers. </p>
</li>
<li><p><strong>Spammy subject lines or content</strong> </p>
</li>
<li><p><strong>Unreliable email infrastructure</strong> with blacklisted IPs, unauthenticated domains, and spam-abused systems </p>
</li>
<li><p><strong>Public domains</strong> such as @gmail.com or @yahoo.com. </p>
</li>
</ul>
<h2 id="heading-how-to-decrease-the-email-bounce-rate-6-tips-to-follow"><strong>How to decrease the email bounce rate? 6 tips to follow</strong></h2>
<p>Not all is lost if your email bounce rates are high. By taking the necessary measures, you can gradually reduce them. Here’s how to improve email bounce rate and keep it as low as possible. </p>
<h3 id="heading-use-legitimate-practices-while-building-email-lists"><strong>Use legitimate practices while building email lists</strong></h3>
<p>Marketing email campaigns rely on email lists and building them requires a lot of time and effort. The easy way out is to purchase ready-made lists and blast out thousands of emails right away. But an easy way certainly doesn’t mean the best way. </p>
<p>Bought email lists usually contain spam traps. Those are recycled email addresses that are no longer in use by real recipients. If you send an email to such addresses, you’ll immediately be labeled as a spammer. As a result, your bounce rates will increase and email deliverability will suffer. </p>
<p>The good practice is to build permission-based email lists i.e. ask your users whether they want to receive marketing emails or not. This can be done by adding a consent checkbox in your sign-up forms. Double opt-in (sending a confirmation email after the user consents to receive marketing emails) is even better. </p>
<p>Showing up unannounced is creepy both in real life and in the world of emails. </p>
<p>All of these measures will reduce your chances of landing in spam folders and getting high bounce rates. </p>
<h3 id="heading-clean-up-and-validate-your-mailing-list-regularly"><strong>Clean up and validate your mailing list regularly</strong></h3>
<p>Email lists are like cars – you’ll face serious consequences unless you maintain them regularly. To do so, you should regularly go through your subscriber list and remove inactive users. Most marketing tools have the option to automate that process. </p>
<p>Another step you should take is validating your lists to remove invalid addresses. These are addresses that don’t exist anymore or have typos. Email bounce rate tools such as ZeroBounce, NeverBounce, Verifalia, etc. will help you check your email lists and keep valid email addresses in them. They won’t be 100% accurate, but they will help you maintain acceptable bounce rates. </p>
<h3 id="heading-test-your-emails-before-sending-them-to-intended-recipients"><strong>Test your emails before sending them to intended recipients</strong></h3>
<p>Testing your emails before sending them to recipients is always a good idea. It will help you eliminate any sending issues beforehand and test email bounce rate to some extent. There are two ways to go about it: messing with dummy email accounts and using dedicated tools. We don’t recommend the first option because it requires too much effort and doesn’t provide comprehensive insights. </p>
<p>One tool you could use is <a target="_blank" href="https://mailtrap.io/email-sandbox/">Mailtrap Email Testing</a>. It’s part of the <a target="_blank" href="https://mailtrap.io/">Mailtrap Email Delivery Platform</a>. Email Testing provides you with a Sandbox to inspect and debug your emails in a staging environment. As it captures all the SMTP traffic, you can safely check the email-sending capabilities of your app and see if your emails get delivered to the inboxes. </p>
<p><a target="_blank" href="https://mailtrap.io/register/signup?ref=header"><strong>Try Mailtrap Email Testing for Free</strong></a></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Mailtrap-Email-Testing-Inbox-.png" alt="Mailtrap Email Testing inbox" /></p>
<p>Apart from that, Email Testing has a Spam Analysis feature that shows you Spam and Blacklist reports. By viewing those, you’ll see where your IP and domain reputation stands. If your spam score is high, it’s likely that your emails will bounce or get blocked by the recipient’s mail server. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Mailtrap-Spam-Analysis-.png" alt="Mailtrap Email Testing spam analysis" /></p>
<p><a target="_blank" href="https://mailtrap.io/register/signup?ref=header"><strong>Start Testing for Free</strong></a></p>
<p>Your testing workflows can be a separate measure to send well-crafted emails or be part of <a target="_blank" href="https://mailtrap.io/blog/email-sending-reputation-audit/">email sending reputation audit</a>. The latter is a comprehensive ‘investigation’ that reveals the main culprits behind your email deliverability. That way, you’ll know for sure what’s causing your bounce rates and work in that direction. </p>
<p>Alternatively, you could hire <a target="_blank" href="https://mailtrap.io/blog/email-deliverability-consultants/">email deliverability consultants</a> who will conduct the audit, provide feedback, and help you plan all the deliverability-related steps. </p>
<h3 id="heading-send-emails-from-a-reliable-email-infrastructure"><strong>Send emails from a reliable email infrastructure</strong></h3>
<p>Sending emails from a reliable <a target="_blank" href="https://mailtrap.io/blog/email-infrastructure/">email infrastructure</a> is a surefire way to reduce and prevent high bounce rates. It will also help you maintain good deliverability rates. The reason is simple: reputable ESPs have a good <a target="_blank" href="https://mailtrap.io/blog/email-ip-reputation/">IP reputation</a> for their shared IPs, as well as an option to use dedicated IPs if the sending volume is high enough. On top, they take strict security measures to keep the spammers at bay.</p>
<p>Typically, ESPs and sending solutions require you to authenticate your domains with <a target="_blank" href="https://www.youtube.com/watch?v=3O42vhFT0j8">SPF</a>, <a target="_blank" href="https://www.youtube.com/watch?v=jy6YMzQZTz8">DKIM</a>, and <a target="_blank" href="https://www.youtube.com/watch?v=zT1wMIz8_IU">DMARC</a> records before you start sending. This adds to your domain’s credibility and lowers the chances of landing in spam folders. Not only that, <a target="_blank" href="https://support.google.com/mail/answer/81126?sjid=12081390133285726533-EU">Google</a> and <a target="_blank" href="https://senders.yahooinc.com/best-practices/">Yahoo</a> now require regular and high-volume senders to have these records in place. You don’t have that option with free email accounts and email domains. Large volumes of emails coming from such addresses immediately raise the yellow flag (a.k.a. spam) among ISPs. </p>
<p>Using an ESP is sort of an industry-standard whether you’re sending email blasts, general marketing campaigns, or transactional emails. </p>
<p>One such software is <a target="_blank" href="https://mailtrap.io/email-sending/">Mailtrap Email Sending</a> we mentioned above – the second solution offered by Mailtrap. It’s an email infrastructure to reach your recipients’ inboxes. This platform has RESTful API and SMTP services. </p>
<p><a target="_blank" href="https://mailtrap.io/register/signup?ref=header"><strong>Try Mailtrap Email Sending for Free</strong></a></p>
<p>To keep your bounce rates in check, Email Sending provides ready-made DNS records for authentication protocols. It runs regular security checks to prevent spam abuse and protect the reputation of shared IPs. As you start sending at least 100K emails a month, you get the option to use a dedicated IP included in your plan. Dedicated IPs have auto warm-ups to prevent email bounces and spam complaints. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Mailtrap-Domain-Verification.png" alt="Mailtrap Email Sending domain verification" /></p>
<p>Email Sending also has strict policies regarding bounce rates. If your emails soft bounce, the platform will attempt to send them 10 more times. If the outcomes are unsuccessful, the emails will be hard bounced and added to your stats. </p>
<p>Hard-bounced emails are added to <a target="_blank" href="https://mailtrap.io/blog/email-suppression-list/">suppression lists</a> automatically to protect your deliverability. You can view and manage those in the ‘Suppressions’ tab, and examine the reasons for each bounce. While you can reactivate any suppressed email address, we strongly recommend against activating invalid addresses. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Mailtrap-Email-Sending-Suppressions.png" alt="Mailtrap Email Sending Suppressions" /></p>
<p><a target="_blank" href="https://mailtrap.io/register/signup?ref=header"><strong>Start Sending for Free</strong></a></p>
<h3 id="heading-craft-non-spammy-email-content"><strong>Craft non-spammy email content</strong></h3>
<p>The spammy email content is another reason why your emails might get considered as spam and bounce. That’s why you should avoid spammy words (‘big bucks’, ‘free money’, ‘million dollars’, etc.) in your subject lines and copies. </p>
<p>Use A/B testing whenever possible. Whether you’re talking to new subscribers or trying to <a target="_blank" href="https://forms.app/en/blog/how-to-conduct-a-survey-online">conduct surveys</a>, it’s a good idea to test various portions of emails separately. Run A/B testing campaigns for subject lines, CTAs, email bodies, body formats, and other parts of your emails. That way, you’ll be sending the content your audience likes, which leads to fewer spam complaints. </p>
<h3 id="heading-create-and-follow-email-marketing-strategy"><strong>Create and follow email marketing strategy</strong></h3>
<p>An <a target="_blank" href="https://mailtrap.io/blog/email-marketing-strategy/">email marketing strategy</a> is a detailed roadmap for your campaigns. As it’s based on comprehensive research, it allows you to tailor your tactics and campaigns to your audiences. With a strategy, you won’t send random emails to random people. Each step will be carefully calculated, resulting in better open, click, and click-through rates. Good audience engagement improves your sender reputation and helps maintain low bounce rates. </p>
<h2 id="heading-key-takeaways"><strong>Key takeaways</strong></h2>
<p>Let’s end this blog post with a few key takeaways: </p>
<ul>
<li><p>Email bounce rate affects your email deliverability </p>
</li>
<li><p>To keep bounce rates low, you should avoid buying mailing lists and run permission-based <a target="_blank" href="https://mailtrap.io/blog/email-marketing">email marketing</a> </p>
</li>
<li><p>Email list validation is a great way to reduce hard bounces </p>
</li>
<li><p>Email infrastructure impacts your bounce rates </p>
</li>
<li><p>It’s important to develop an email marketing strategy and run high-quality campaigns. </p>
</li>
</ul>
<p>And with this good-ol’ meme, farewell folks! </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/04/Email-bounce-rate-meme.jpeg" alt="Email bounce rate meme" /></p>
<p>We appreciate the you chose this article to find out <a target="_blank" href="https://mailtrap.io/blog/email-bounce-rate/">what is average email bounce rate</a>. If you want to find more interesting content on related topics, follow Mailtrap blog!</p>
]]></content:encoded></item><item><title><![CDATA[How to Test Emails in Your Python App]]></title><description><![CDATA[Python provides multiple ways of testing emails. It has native options and the ability to integrate with a third-party tool, such as Mailtrap Email Testing. 
I’ve recently explored a few approaches and will share my experience in this tutorial. I’ll ...]]></description><link>https://ketevanbostoganashvili.hashnode.dev/how-to-test-emails-in-your-python-app</link><guid isPermaLink="true">https://ketevanbostoganashvili.hashnode.dev/how-to-test-emails-in-your-python-app</guid><dc:creator><![CDATA[Ketevan Bostoganashvili]]></dc:creator><pubDate>Fri, 05 Jan 2024 14:41:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1704465218281/589822b6-b22a-4153-873e-ff1538bc9ed1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Python provides multiple ways of testing emails. It has native options and the ability to integrate with a third-party tool, such as Mailtrap Email Testing. </p>
<p>I’ve recently explored a few approaches and will share my experience in this tutorial. I’ll cover native methods such as unit tests + aiosmtpd, Python’s subprocess function, as well as unit tests’ mock object library.</p>
<p>I’ll also demonstrate how to integrate and test emails in Python with Mailtrap Email Testing. </p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/4-QZn5de72g">https://youtu.be/4-QZn5de72g</a></div>
<p> </p>
<h2 id="heading-native-ways-of-testing-emails-in-python"><strong>Native ways of testing emails in Python</strong></h2>
<p>Let’s start with the native ways of testing Python emails. </p>
<h3 id="heading-using-unit-tests-and-aiosmtpd"><strong>Using unit tests and aiosmtpd</strong></h3>
<p>Aiosmtpd is a library that lets you set up a local SMTP (Simple Mail Transfer Protocol) server. This will create a testing environment and handle email traffic internally. So, your test emails won’t reach the recipients. Refer to aiosmtpd’s <a target="_blank" href="https://github.com/aio-libs/aiosmtpd">GitHub page</a> for more information. </p>
<p>I’ll create a test for a simple text email. </p>
<p><strong>Prerequisites:</strong> </p>
<ul>
<li>Python 3.7 and up. </li>
</ul>
<p><em>Note: I added the code snippets below in the</em> <a target="_blank" href="https://github.com/aio-libs/aiosmtpd"><em>tests.py</em></a> <em>file.</em> </p>
<p>To install aiosmtpd, run the <code>pip install aiosmtpd</code> command. </p>
<p>Run the server with <code>python -m aiosmtpd -n</code> command. </p>
<p>I’ll use the unit test framework, a standard library in all versions of Python since 2.1, and the smtplib library. smtplib module uses standard RFC 821 protocol for formatting messages. </p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> unittest <span class="hljs-keyword">import</span> TestCase
<span class="hljs-keyword">import</span> smtplib
</code></pre>
<p>Create a class that will inherit the unit test from the <code>TestCase</code> object and configure the test case. </p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailTestCase</span>(<span class="hljs-params">TestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_send_email</span>(<span class="hljs-params">self</span>):</span>
        sender_email = <span class="hljs-string">"your_email@gmail.com"</span>
        receiver_email = <span class="hljs-string">"receiver_email@example.com"</span>
        message = <span class="hljs-string">"This is a test email."</span>
</code></pre>
<p>The <code>sender_email</code> and <code>receiver_email</code> variables can be populated with sample data as we simulate email sending. The message variable should contain the desired email body. </p>
<p>The next step is to send a test email using the smtplib. </p>
<pre><code class="lang-python"><span class="hljs-keyword">with</span> smtplib.SMTP(host=<span class="hljs-string">"localhost"</span>, port=<span class="hljs-number">8025</span>) <span class="hljs-keyword">as</span> server:
            server.ehlo()
            server.sendmail(sender_email, receiver_email, message)
</code></pre>
<p>Here, we create a new instance of an SMTP client. By default, the server works on <a target="_blank" href="https://github.com/aio-libs/aiosmtpd">localhost</a> with port number 8025. We also initiated an SMTP handshake with EHLO and added the sendmail method to send the emails. The sendmail method takes three arguments – <code>sender_email</code>, <code>receiver_email</code>, and <code>message</code>. </p>
<p>The script is now ready. Here’s the full sample: </p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> unittest <span class="hljs-keyword">import</span> TestCase
<span class="hljs-keyword">import</span> smtplib

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailTestCase</span>(<span class="hljs-params">TestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_send_email</span>(<span class="hljs-params">self</span>):</span>
        sender_email = <span class="hljs-string">"your_email@gmail.com"</span>
        receiver_email = <span class="hljs-string">"receiver_email@example.com"</span>
        message = <span class="hljs-string">"This is a test email."</span>

        <span class="hljs-keyword">with</span> smtplib.SMTP(host=<span class="hljs-string">"localhost"</span>, port=<span class="hljs-number">8025</span>) <span class="hljs-keyword">as</span> server:
            server.ehlo()
            server.sendmail(sender_email, receiver_email, message)
</code></pre>
<p>To run the Python code, use the Run button. </p>
<p>If the test passes, you’ll see a message similar to the one below. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-5.png" alt="A message indicating successful Python test email " /></p>
<p>You’ll also see that the email was sent in the terminal. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image.png" alt="Success message in terminal " /></p>
<h4 id="heading-limitations-of-this-approach"><strong>Limitations of this approach</strong></h4>
<p>While this approach can be useful for testing simple email-sending scripts, I found that it has multiple limitations: </p>
<ul>
<li><p>Each time I ran the tests, I had to type aiosmtpd manually. This is okay for small and occasional tests, but it’s a huge pain during scaled testing. </p>
</li>
<li><p>As we’re simulating the process of sending emails, we can’t test real-world email delivery. </p>
</li>
<li><p>This setup doesn’t allow for testing high email load. </p>
</li>
<li><p>It doesn’t allow testing advanced email functionalities or features, such as client rendering, for example.</p>
</li>
</ul>
<h3 id="heading-using-pythons-subprocess-function-with-unit-tests-and-aiosmtpd"><strong>Using Python’s subprocess function with unit tests and aiosmtpd</strong></h3>
<p>One way to automate processes while using unit tests and aisosmtpd is Python’s subprocess function. It allows us to run an external program from the Python script. </p>
<p>I first had to import the subprocess function and time module to improve and enhance the previous script. I’ll use the latter to wait for a few seconds before the server is ready. </p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> unittest <span class="hljs-keyword">import</span> TestCase
<span class="hljs-keyword">import</span> smtplib
<span class="hljs-keyword">import</span> subprocess
<span class="hljs-keyword">import</span> time
</code></pre>
<p>Then, I added the <code>setUp</code> method. It prepares the environment to run the server. <code>subprocess.Popen</code> function will execute the command in a new process. </p>
<p>In this case, the command is <code>exec python -m aiosmtpd -n</code>, meaning that the server will run in a new process. </p>
<p><code>shell-True</code> will allow us to execute the command using the shell. We won’t have to create a new terminal. Rather, the process will run in the background. </p>
<p>As mentioned, <code>time.sleep(2)</code> will pause the execution of the script for 2 seconds to give the server enough time to be ready. </p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setUp</span>(<span class="hljs-params">self</span>):</span>
    self.process = subprocess.Popen(args=<span class="hljs-string">'exec python -m aiosmtpd -n'</span>, shell=<span class="hljs-literal">True</span>)
    time.sleep(<span class="hljs-number">2</span>)
</code></pre>
<p>The next step is to add a <code>tearDown</code> method, which will terminate the subprocess and wait for the process to finish termination. </p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">tearDown</span>(<span class="hljs-params">self</span>):</span>
    self.process.kill()
    self.process.wait()
</code></pre>
<p>The test itself is essentially the same, but I added one more assertion. It checks if the server is working and the socket is open. </p>
<pre><code class="lang-python">self.assertIsNotNone(server.sock)
</code></pre>
<p>Here’s the complete code sample: </p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> unittest <span class="hljs-keyword">import</span> TestCase
<span class="hljs-keyword">import</span> smtplib
<span class="hljs-keyword">import</span> subprocess
<span class="hljs-keyword">import</span> time

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailTestCase</span>(<span class="hljs-params">TestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setUp</span>(<span class="hljs-params">self</span>):</span>
        self.process = subprocess.Popen(args=<span class="hljs-string">'exec python -m aiosmtpd -n'</span>, shell=<span class="hljs-literal">True</span>)
        time.sleep(<span class="hljs-number">2</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_send_email</span>(<span class="hljs-params">self</span>):</span>
        sender_email = <span class="hljs-string">"your_email@gmail.com"</span>
        receiver_email = <span class="hljs-string">"receiver_email@example.com"</span>
        message = <span class="hljs-string">"This is a test email."</span>
        <span class="hljs-keyword">with</span> smtplib.SMTP(host=<span class="hljs-string">"localhost"</span>, port=<span class="hljs-number">8025</span>) <span class="hljs-keyword">as</span> server:
            server.ehlo()
            server.sendmail(sender_email, receiver_email, message)
            self.assertIsNotNone(server.sock)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">tearDown</span>(<span class="hljs-params">self</span>):</span>
        self.process.kill()
        self.process.wait()
</code></pre>
<p>At this point, we can run the script with the <em>Run</em> button. </p>
<p>The tests were successful, meaning the server was turned on and off as expected. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-3.png" alt="Python test email success message" /></p>
<h4 id="heading-running-the-script-from-the-console"><strong>Running the script from the console</strong></h4>
<p>As you’ll notice, I used the Run button to run the scripts in the previous examples. I’ll add the <em>if</em> statement to run the code from the console, modify the unit test import, and reference the <code>unittest.TestCase</code> with the <code>EmailTestCase</code> class definition. </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest
<span class="hljs-keyword">import</span> smtplib
<span class="hljs-keyword">import</span> subprocess
<span class="hljs-keyword">import</span> time

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailTestCase</span>(<span class="hljs-params">unittest.TestCase</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setUp</span>(<span class="hljs-params">self</span>):</span>
        self.process = subprocess.Popen(args=<span class="hljs-string">'exec python -m aiosmtpd -n'</span>, shell=<span class="hljs-literal">True</span>)
        time.sleep(<span class="hljs-number">2</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_send_email</span>(<span class="hljs-params">self</span>):</span>
        sender_email = <span class="hljs-string">"your_email@gmail.com"</span>
        receiver_email = <span class="hljs-string">"receiver_email@example.com"</span>
        message = <span class="hljs-string">"This is a test email."</span>

        <span class="hljs-keyword">with</span> smtplib.SMTP(host=<span class="hljs-string">"localhost"</span>, port=<span class="hljs-number">8025</span>) <span class="hljs-keyword">as</span> server:
            server.ehlo()
            server.sendmail(sender_email, receiver_email, message)
            self.assertIsNotNone(server.sock)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">tearDown</span>(<span class="hljs-params">self</span>):</span>
        self.process.kill()
        self.process.wait()

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    unittest.main()
</code></pre>
<p>With the updated setup, we can now run the code directly from the console using the <code>python</code> <a target="_blank" href="http://tests.py"><code>tests.py</code></a> command. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-16.png" alt /></p>
<h4 id="heading-testing-if-the-script-can-read-files"><strong>Testing if the script can read files</strong></h4>
<p>The last modification in the script was to enable it to read emails from the file. This would allow me to test if the variables in the template were substituted correctly. I went with the simple setup once again. </p>
<p>So, I created a new template file with only a message variable. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-12.png" alt /></p>
<p>I went back to the <a target="_blank" href="http://tests.py"><em>tests.py</em></a> file and added a <em>with</em> statement which would be responsible for opening and closing files. </p>
<pre><code class="lang-python"><span class="hljs-keyword">with</span> open(<span class="hljs-string">'template.html'</span>) <span class="hljs-keyword">as</span> file:
    template = file.read()
</code></pre>
<p>Using the <code>format</code> function, I added the message to the template. </p>
<pre><code class="lang-python">template = template.format(message=message)
</code></pre>
<p>And inserted the template into the sendmail function. </p>
<pre><code class="lang-python">server.sendmail(sender_email, receiver_email, template)
</code></pre>
<p>The whole script will look something like this: </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest
<span class="hljs-keyword">import</span> smtplib
<span class="hljs-keyword">import</span> subprocess
<span class="hljs-keyword">import</span> time

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailTestCase</span>(<span class="hljs-params">unittest.TestCase</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setUp</span>(<span class="hljs-params">self</span>):</span>
        self.process = subprocess.Popen(args=<span class="hljs-string">'exec python -m aiosmtpd -n'</span>, shell=<span class="hljs-literal">True</span>)
        time.sleep(<span class="hljs-number">2</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_send_email</span>(<span class="hljs-params">self</span>):</span>
        sender_email = <span class="hljs-string">"your_email@gmail.com"</span>
        receiver_email = <span class="hljs-string">"receiver_email@example.com"</span>
        message = <span class="hljs-string">"This is a test email."</span>

        <span class="hljs-keyword">with</span> open(<span class="hljs-string">'template.html'</span>) <span class="hljs-keyword">as</span> file:
            template = file.read()

        template = template.format(message=message)
        <span class="hljs-keyword">with</span> smtplib.SMTP(host=<span class="hljs-string">"localhost"</span>, port=<span class="hljs-number">8025</span>) <span class="hljs-keyword">as</span> server:
            server.ehlo()
            server.sendmail(sender_email, receiver_email, template)
            self.assertIsNotNone(server.sock)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">tearDown</span>(<span class="hljs-params">self</span>):</span>
        self.process.kill()
        self.process.wait()

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    unittest.main()
</code></pre>
<p>Run the code with python <a target="_blank" href="http://test.py">test.py</a> and check the output. The message variable was replaced correctly, so the test was successful. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-7.png" alt="Email test results " /></p>
<h4 id="heading-limitations-of-this-approach-1"><strong>Limitations of this approach</strong></h4>
<p>Similar to using aiosmtpd and unit tests, this expanded approach also has its limitations: </p>
<ul>
<li><p>Doesn’t allow for testing how complex HTML will render on mobile or desktop devices; </p>
</li>
<li><p>Doesn’t allow for deliverability testing;</p>
</li>
<li><p>Doesn’t allow for checking client support for HTML emails;</p>
</li>
<li><p>Doesn’t allow for testing the communication between the script and external mail servers; </p>
</li>
<li><p>Relies on aiosmtpd and port 8025. Tests may fail if the server isn’t set up correctly. </p>
</li>
</ul>
<h3 id="heading-using-the-unit-tests-mock-object-library"><strong>Using the unit test’s mock object library</strong></h3>
<p>Another option for testing emails in Python natively is the unit test’s mock object library. It lets you mock the SMTP server connection without sending the emails. </p>
<p>Here’s the script: </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest
<span class="hljs-keyword">from</span> email.mime.text <span class="hljs-keyword">import</span> MIMEText
<span class="hljs-keyword">from</span> unittest.mock <span class="hljs-keyword">import</span> patch
<span class="hljs-keyword">import</span> smtplib

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_email</span>(<span class="hljs-params">server, port, subject, message, from_addr, to_addr</span>):</span>

    smtp_user = <span class="hljs-string">'username'</span>
    smtp_password = <span class="hljs-string">'password'</span>
    msg = MIMEText(message)
    msg[<span class="hljs-string">'From'</span>] = from_addr
    msg[<span class="hljs-string">'To'</span>] = to_addr
    msg[<span class="hljs-string">'Subject'</span>] = subject
    <span class="hljs-keyword">with</span> smtplib.SMTP(server, port) <span class="hljs-keyword">as</span> server:
        server.starttls()
        server.login(smtp_user, smtp_password)
        server.send_message(msg)
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TestEmailSending</span>(<span class="hljs-params">unittest.TestCase</span>):</span>
<span class="hljs-meta">    @patch('smtplib.SMTP')</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_send_email</span>(<span class="hljs-params">self, mock_smtp</span>):</span>
        <span class="hljs-comment"># Arrange: Setup our expectations</span>
        subject = <span class="hljs-string">"Test Subject"</span>
        message = <span class="hljs-string">"Hello, this is a test."</span>
        from_addr = <span class="hljs-string">'from@example.com'</span>
        to_addr = <span class="hljs-string">'to@example.com'</span>
        server = <span class="hljs-string">"sandbox.smtp.mailtrap.io"</span>
        port = <span class="hljs-number">587</span>
        <span class="hljs-comment"># Act: Call the send_email function</span>
        send_email(server, port, subject, message, from_addr, to_addr)

        <span class="hljs-comment"># Assert: Check if the right calls were made on the SMTP object</span>
        mock_smtp.assert_called_with(server, port)
        instance = mock_smtp.return_value.__enter__.return_value
        instance.send_message.assert_called_once()
        call_args = instance.send_message.call_args[<span class="hljs-number">0</span>]
        sent_email = call_args[<span class="hljs-number">0</span>]

        <span class="hljs-comment"># Verify the email content</span>
        self.assertEqual(sent_email[<span class="hljs-string">'Subject'</span>], subject)
        self.assertEqual(sent_email[<span class="hljs-string">'From'</span>], from_addr)
        self.assertEqual(sent_email[<span class="hljs-string">'To'</span>], to_addr)
        self.assertEqual(sent_email.get_payload(), message)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    unittest.main()
</code></pre>
<p>The provided code defines a function and includes a test class, <code>TestEmailSending</code>, using Python’s unit test framework to test this function. </p>
<p>The <code>send_email</code> function takes server details, subject, message body, sender’s address, and recipient’s address as parameters, creates an email (<code>MIMEText</code>) object with these details, and then logs into an SMTP server to send it. </p>
<p>In the test case, the <code>smtplib.SMTP</code> class is mocked using the <code>unittest.mock.patch</code>, allowing the test to verify that the SMTP server is called with the correct parameters without actually sending an email. </p>
<p>The test checks if the <code>send_message</code> method of the SMTP instance is called correctly and asserts that the email’s subject, from address, to address, and payload match the expected values.</p>
<h4 id="heading-limitations-of-this-approach-2"><strong>Limitations of this approach</strong></h4>
<ul>
<li><p>The mock object library isn’t sufficient for detecting issues with implementation;</p>
</li>
<li><p>Doesn’t allow for checking client support for HTML emails;</p>
</li>
<li><p>Doesn’t allow for testing how complex HTML will render on mobile or desktop devices. </p>
</li>
</ul>
<h2 id="heading-how-to-test-emails-in-python-with-mailtrap-via-smtp"><strong>How to test emails in Python with Mailtrap via SMTP</strong></h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/1pQJvaF2oTo">https://youtu.be/1pQJvaF2oTo</a></div>
<p> </p>
<p>To address the limitations of the native methods, I decided to use <a target="_blank" href="https://mailtrap.io/email-sandbox/">Mailtrap Email Testing</a>. It’s an Email Sandbox that provides a safe environment for inspecting and debugging emails in staging, QA, and dev environments. </p>
<p>I used Email Testing to run functional and deliverability tests, check email formatting, analyze the content for spam, check attachments, and test error handling. </p>
<p><em>You’ll need an account to use it, and you can quickly create it by opening the</em> <a target="_blank" href="https://mailtrap.io/register/signup?ref=header"><em>signup page</em></a><em>. Once the account is up and running, we can go straight to testing.</em> </p>
<h3 id="heading-functional-testing"><strong>Functional testing</strong></h3>
<p>We’ll need a slightly different script in this case. Create a new <code>EmailTestCase</code> class and add sample data. Here, <code>test_mailtrap</code> is a method that will send a test email to Mailtrap. </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailTestCase</span>(<span class="hljs-params">unittest.TestCase</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_mailtrap</span>(<span class="hljs-params">self</span>):</span>
        sender_email = <span class="hljs-string">'sender@example.com'</span>
        recipient_email = <span class="hljs-string">'recipient@example.com'</span>
        subject = <span class="hljs-string">'Test Email'</span>
        body = <span class="hljs-string">'This is a test email sent from the SMTP server.'</span>
</code></pre>
<p>The next step is to import the built-in <code>EmailMessage</code> object. </p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> email.message <span class="hljs-keyword">import</span> EmailMessage
</code></pre>
<p>Using it, we’ll build a message and add the sample data to it. </p>
<pre><code class="lang-python">msg = EmailMessage()
msg[<span class="hljs-string">'From'</span>] = sender_email
msg[<span class="hljs-string">'To'</span>] = recipient_email
msg[<span class="hljs-string">'Subject'</span>] = subject
msg.set_content(body)
</code></pre>
<p>The last step is to connect to Mailtrap Email Testing’s fake SMTP server. For that, I’ll use smtplib and the with statement. At this point, I’ll need Email Testing’s SMTP credentials. To access them, go to <em>Email Testing → My Inbox → SMTP Settings</em> and click <em>Show Credentials</em>. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-17.png" alt /></p>
<p>Copy the <em>Host</em>, <em>Username</em>, and <em>Password</em>, and return to the Python project. Create a new instance of the SMTP client and connect to the server using the host and port. </p>
<p>Call the <code>server.login</code> method and pass a username and password to it.  </p>
<pre><code class="lang-python"><span class="hljs-keyword">with</span> smtplib.SMTP(host=<span class="hljs-string">"sandbox.smtp.mailtrap.io"</span>, port=<span class="hljs-number">2525</span>) <span class="hljs-keyword">as</span> server:
    server.login(user=<span class="hljs-string">"your_username"</span>, PASSWORD)
    server.send_message(msg)
</code></pre>
<p><em>Note: Your_username is a placeholder. You should add your actual username here.</em> </p>
<p>For security reasons, I’ve stored the password in a separate folder. So, I’ll import it. </p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> variables <span class="hljs-keyword">import</span> PASSWORD
</code></pre>
<p>The email-testing script is now ready. </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> unittest
<span class="hljs-keyword">import</span> smtplib

<span class="hljs-keyword">from</span> email.message <span class="hljs-keyword">import</span> EmailMessage

<span class="hljs-keyword">from</span> variables <span class="hljs-keyword">import</span> PASSWORD

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">EmailTestCase</span>(<span class="hljs-params">unittest.TestCase</span>):</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_mailtrap</span>(<span class="hljs-params">self</span>):</span>
        sender_email = <span class="hljs-string">'sender@example.com'</span>
        recipient_email = <span class="hljs-string">'recipient@example.com'</span>
        subject = <span class="hljs-string">'Test Email'</span>
        body = <span class="hljs-string">'This is a test email sent from the SMTP server.'</span>
        msg = EmailMessage()
        msg[<span class="hljs-string">'From'</span>] = sender_email
        msg[<span class="hljs-string">'To'</span>] = recipient_email
        msg[<span class="hljs-string">'Subject'</span>] = subject
        msg.set_content(body)

        <span class="hljs-keyword">with</span> smtplib.SMTP(host=<span class="hljs-string">"sandbox.smtp.mailtrap.io"</span>, port=<span class="hljs-number">2525</span>) <span class="hljs-keyword">as</span> server:
            server.login(user=<span class="hljs-string">"your_username"</span>, PASSWORD)
            server.send_message(msg)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    unittest.main()
</code></pre>
<p>I ran the code with the python <a target="_blank" href="https://mailtrap.io/register/signup?ref=header">tests.py</a> command. And the email arrived in the Email Testing inbox within seconds. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-14.png" alt /></p>
<p><strong>Test results:</strong> </p>
<ul>
<li>Verified whether the <code>EmailMessage</code> object was correctly populated with the sender’s email, recipient’s email address, subject, and body text. I checked the body by going to the <em>Text</em> tab and verified from, to, and subject from the <em>Tech Info</em> and <em>Raw</em> tabs. </li>
</ul>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-2.png" alt="Python test email in Mailtrap Email testing " /></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-10.png" alt="Checking the headers in Python test email using Mailtrap Email Testing " /></p>
<ul>
<li><p>Revealed that the code established an SMTP connection successfully. </p>
</li>
<li><p>Revealed that the SMTP authentication process was correct. </p>
</li>
<li><p>Confirmed that the text message formatting was correct and, as a result, it was successfully sent through the SMTP server.</p>
</li>
<li><p>Verified that <code>send_message</code> method of the <code>smtplib.SMTP</code> class was called with the correct parameters. </p>
</li>
</ul>
<h3 id="heading-checking-email-formatting-and-html-code"><strong>Checking email formatting and HTML code</strong></h3>
<p>Next up in my tests were: </p>
<ul>
<li><p>Checking whether the message body in plain text and HTML versions would be the same; </p>
</li>
<li><p>Checking the mobile, desktop, and tablet previews; </p>
</li>
<li><p>Analyzing HTML code to see if it contained any unsupported elements. </p>
</li>
</ul>
<p>For that, I sent a simple HTML email to my virtual inbox using the following lines of code. I used an email-sending script, not a unit test in this case, since the email would still get captured in the inbox. For more information on sending HTML emails from Python, refer to <a target="_blank" href="https://mailtrap.io/blog/python-send-html-email/">this blog post</a>. </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> smtplib
<span class="hljs-keyword">from</span> email.mime.text <span class="hljs-keyword">import</span> MIMEText
<span class="hljs-keyword">from</span> email.mime.multipart <span class="hljs-keyword">import</span> MIMEMultipart

port = <span class="hljs-number">2525</span>
smtp_server = <span class="hljs-string">"sandbox.smtp.mailtrap.io"</span>
login = <span class="hljs-string">"your_username"</span>
password = <span class="hljs-string">"your_password"</span>

sender_email = <span class="hljs-string">"sender@example.com"</span>
receiver_email = <span class="hljs-string">"recipient@example.com"</span>
message = MIMEMultipart(<span class="hljs-string">"alternative"</span>)
message[<span class="hljs-string">"Subject"</span>] = <span class="hljs-string">"HTML test"</span>
message[<span class="hljs-string">"From"</span>] = sender_email
message[<span class="hljs-string">"To"</span>] = receiver_email

<span class="hljs-comment"># write the text/plain part</span>
text = <span class="hljs-string">"""\
Hi,
Check out the new post on the Mailtrap blog:
SMTP Server for Testing: Cloud-based or Local?
https://blog.mailtrap.io/2018/09/27/cloud-or-local-smtp-server/
Feel free to let us know what content would be useful for you!"""</span>

<span class="hljs-comment"># write the HTML part</span>
html = <span class="hljs-string">"""\
&lt;html&gt;
  &lt;body&gt;
    &lt;p&gt;Hi,&lt;br&gt;
      Check out the new post on the Mailtrap blog:&lt;/p&gt;
    &lt;p&gt;&lt;a href="https://blog.mailtrap.io/2018/09/27/cloud-or-local-smtp-server"&gt;SMTP Server for Testing: Cloud-based or Local?&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt; Feel free to &lt;strong&gt;let us&lt;/strong&gt; know what content would be useful for you!&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;
"""</span>

<span class="hljs-comment"># convert both parts to MIMEText objects and add them to the MIMEMultipart message</span>
part1 = MIMEText(text, <span class="hljs-string">"plain"</span>)
part2 = MIMEText(html, <span class="hljs-string">"html"</span>)
message.attach(part1)
message.attach(part2)

<span class="hljs-keyword">with</span> smtplib.SMTP(<span class="hljs-string">"sandbox.smtp.mailtrap.io"</span>, <span class="hljs-number">2525</span>) <span class="hljs-keyword">as</span> server:
    server.login(login, password)
    server.sendmail(
        sender_email, receiver_email, message.as_string()
    )

print(<span class="hljs-string">'Sent'</span>)
</code></pre>
<p><strong>Test results:</strong> </p>
<ul>
<li>Verified that the HTML message wasn’t broken on mobile, desktop, or tablet views. </li>
</ul>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-4.png" alt="Desktop, mobile, and tablet previews in Mailtrap Email Testing " /></p>
<ul>
<li>Confirmed that the text content was the same as the HTML content. </li>
</ul>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-8.png" alt="HTML and Text content comparison in Mailtrap Email Testing " /></p>
<ul>
<li>Found out that my email contained one element that email clients would support partially or wouldn’t support at all. </li>
</ul>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-13.png" alt="Checking client support in Mailtrap Email Testing " /></p>
<h3 id="heading-deliverability-testing"><strong>Deliverability testing</strong></h3>
<p>To extend my tests, I opened the <em>Spam Analysis</em> tab. This showed the Spam Report with spam score, as well as spam points with descriptions. This is useful for improving the template if it exceeds the threshold of 5. Spam tests are run with the help of the SpamAssassin filter. </p>
<p><strong>Test results:</strong></p>
<ul>
<li>Verified that the spam score of the email was below the threshold of 5. </li>
</ul>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-15.png" alt="Spam test results " /></p>
<ul>
<li>Checked the Blacklist Report to see if my domain would be listed in any of the blocklists. </li>
</ul>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-9.png" alt="Blacklist test results. " /></p>
<ul>
<li>Verified that my emails would be delivered to the recipients’ inboxes if I were to send them on prod. </li>
</ul>
<h3 id="heading-checking-the-attachments"><strong>Checking the attachments</strong></h3>
<p>I also wanted to see if the email-sending script would attach, encode, and send attachments correctly. Attachments are MIME objects. Encoding implies using a base64 module that encodes all binary data with ASCII characters. </p>
<p>I simply added Email Testing SMTP credentials to this script and waited for the email to arrive in the virtual inbox. </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> smtplib

<span class="hljs-keyword">from</span> email <span class="hljs-keyword">import</span> encoders
<span class="hljs-keyword">from</span> email.mime.base <span class="hljs-keyword">import</span> MIMEBase
<span class="hljs-keyword">from</span> email.mime.multipart <span class="hljs-keyword">import</span> MIMEMultipart
<span class="hljs-keyword">from</span> email.mime.text <span class="hljs-keyword">import</span> MIMEText

port = <span class="hljs-number">2525</span>
smtp_server = <span class="hljs-string">"sandbox.smtp.mailtrap.io"</span>
login = <span class="hljs-string">"your_username"</span> 
password = <span class="hljs-string">"your_password"</span>

subject = <span class="hljs-string">"An example of boarding pass"</span>
sender_email = <span class="hljs-string">"mailtrap@example.com"</span>
receiver_email = <span class="hljs-string">"new@example.com"</span>

message = MIMEMultipart()
message[<span class="hljs-string">"From"</span>] = sender_email
message[<span class="hljs-string">"To"</span>] = receiver_email
message[<span class="hljs-string">"Subject"</span>] = subject

body = <span class="hljs-string">"This is an example of how you can send a boarding pass in attachment with Python"</span>
message.attach(MIMEText(body, <span class="hljs-string">"plain"</span>))

filename = <span class="hljs-string">"yourBP.pdf"</span>

<span class="hljs-keyword">with</span> open(filename, <span class="hljs-string">"rb"</span>) <span class="hljs-keyword">as</span> attachment:
    part = MIMEBase(<span class="hljs-string">"application"</span>, <span class="hljs-string">"octet-stream"</span>)
    part.set_payload(attachment.read())

encoders.encode_base64(part)

part.add_header(
    <span class="hljs-string">"Content-Disposition"</span>,
    <span class="hljs-string">f"attachment; filename= <span class="hljs-subst">{filename}</span>"</span>,
)

message.attach(part)
text = message.as_string()

<span class="hljs-keyword">with</span> smtplib.SMTP(<span class="hljs-string">"sandbox.smtp.mailtrap.io"</span>, <span class="hljs-number">2525</span>) <span class="hljs-keyword">as</span> server:
    server.login(login, password)
    server.sendmail(
        sender_email, receiver_email, text
    )
print(<span class="hljs-string">'Sent'</span>)
</code></pre>
<p>This code snippet sends an email with a PDF attachment. It assumes that the file is located in the same directory in which you run your Python script. The attach method adds the attachment to the message and converts it into a string. </p>
<p>With a similar method, you could also test other types of attachments. In that case, you should simply use an appropriate class such as <a target="_blank" href="https://mailtrap.io/blog/python-send-html-email/"><code>email.mime.audio</code></a><code>.MIMEAudio</code> or <code>email.mime.image.MIMEImage</code>. Read <a target="_blank" href="https://docs.python.org/3/library/email.mime.html">Python docs</a> for more information. </p>
<p>This is what it will look like in the Email Testing inbox. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-1.png" alt="Testing attachments with Mailtrap Email Testing " /></p>
<p><strong>Test results:</strong> </p>
<ul>
<li><p>Verified that the script sends an email with an attachment successfully;</p>
</li>
<li><p>Verified that the file path was configured properly. </p>
</li>
</ul>
<h3 id="heading-testing-error-handling"><strong>Testing error handling</strong></h3>
<p>The final test I ran with SMTP was to check error handling. I sent emails using the smtplib module once again, but this time with try and except blocks. </p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> smtplib
<span class="hljs-keyword">from</span> socket <span class="hljs-keyword">import</span> gaierror

port = <span class="hljs-number">2525</span>
smtp_server = <span class="hljs-string">"sandbox.smtp.mailtrap.io"</span>
login = <span class="hljs-string">"your_username"</span>
password = <span class="hljs-string">"your_password"</span>
sender = <span class="hljs-string">"sender@example.com"</span>
receiver = <span class="hljs-string">"recipient@example.com"</span>
message = <span class="hljs-string">f"""\
Subject: Test email
To: <span class="hljs-subst">{receiver}</span>
From: <span class="hljs-subst">{sender}</span>

This is my test message with Python."""</span>

<span class="hljs-keyword">try</span>:
    <span class="hljs-keyword">with</span> smtplib.SMTP(smtp_server, port) <span class="hljs-keyword">as</span> server:
        server.login(login, password)
        server.sendmail(sender, receiver, message)
    print(<span class="hljs-string">'Sent'</span>)
<span class="hljs-keyword">except</span> (gaierror, ConnectionRefusedError):
    print(<span class="hljs-string">'Failed to connect to the server. Bad connection settings?'</span>)
<span class="hljs-keyword">except</span> smtplib.SMTPServerDisconnected:
    print(<span class="hljs-string">'Failed to connect to the server. Wrong user/password?'</span>)
<span class="hljs-keyword">except</span> smtplib.SMTPException <span class="hljs-keyword">as</span> e:
    print(<span class="hljs-string">'SMTP error occurred: '</span> + str(e))
</code></pre>
<p>This script will: </p>
<ul>
<li><p>Catch <code>gaierror</code> and <code>ConnectionRefusedError</code> exceptions if there are issues connecting to the SMTP server;</p>
</li>
<li><p>Catch <code>smtplib.SMTPServerDisconnected</code> exception if the server disconnects unexpectedly (when login credentials are invalid, for example);</p>
</li>
<li><p>Catch <code>smtplib.SMTPException</code> exception for all the other SMTP errors. </p>
</li>
<li><p>Print the specific error message received from the server. </p>
</li>
</ul>
<p><a target="_blank" href="https://mailtrap.io/register/signup"><strong>Start Testing Python Emails with Mailtrap</strong></a></p>
<h2 id="heading-how-to-test-emails-in-python-with-mailtrap-via-api"><strong>How to test emails in Python with Mailtrap via API</strong></h2>
<p>Mailtrap Email Testing also provides an option to test your emails using API. It’s based on REST principles and returns calls as JSON objects. All the details about the Email Testing API are covered in the <a target="_blank" href="https://api-docs.mailtrap.io/docs/mailtrap-api-docs/a2041e813d169-email-testing-api">API docs</a>. </p>
<p>To make API requests, you’ll need your API token and inbox ID. </p>
<ol>
<li>Go to Settings → API Tokens, and click Add Token. </li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-6.png" alt="Creating an API token for Mailtrap Email testing " /></p>
<ol>
<li>Create a token for the desired project and inbox. </li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-9.png" alt="Adding API token " /></p>
<ol>
<li>Once the token is ready, go to the desired inbox. Check the URL – the inbox ID is the 7-digit number between inboxes/ and /messages. </li>
</ol>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/12/image-11.png" alt="Copying the Inbox ID" /></p>
<p>A sample API request looks something like this:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> http.client

conn = http.client.HTTPSConnection(<span class="hljs-string">"sandbox.api.mailtrap.io"</span>)

payload = <span class="hljs-string">"{\n  \"to\": [\n    {\n      \"email\": \"john_doe@example.com\",\n      \"name\": \"John Doe\"\n    }\n  ],\n  \"cc\": [\n    {\n      \"email\": \"jane_doe@example.com\",\n      \"name\": \"Jane Doe\"\n    }\n  ],\n  \"bcc\": [\n    {\n      \"email\": \"james_doe@example.com\",\n      \"name\": \"Jim Doe\"\n    }\n  ],\n  \"from\": {\n    \"email\": \"sales@example.com\",\n    \"name\": \"Example Sales Team\"\n  },\n  \"attachments\": [\n    {\n      \"content\": \"PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KCiAgICA8aGVhZD4KICAgICAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICAgICAgPG1ldGEgaHR0cC1lcXVpdj0iWC1VQS1Db21wYXRpYmxlIiBjb250ZW50PSJJRT1lZGdlIj4KICAgICAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCI+CiAgICAgICAgPHRpdGxlPkRvY3VtZW50PC90aXRsZT4KICAgIDwvaGVhZD4KCiAgICA8Ym9keT4KCiAgICA8L2JvZHk+Cgo8L2h0bWw+Cg==\",\n      \"filename\": \"index.html\",\n      \"type\": \"text/html\",\n      \"disposition\": \"attachment\"\n    }\n  ],\n  \"custom_variables\": {\n    \"user_id\": \"45982\",\n    \"batch_id\": \"PSJ-12\"\n  },\n  \"headers\": {\n    \"X-Message-Source\": \"dev.mydomain.com\"\n  },\n  \"subject\": \"Your Example Order Confirmation\",\n  \"text\": \"Congratulations on your order no. 1234\",\n  \"category\": \"API Test\"\n}"</span>

headers = {
    <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">"application/json"</span>,
    <span class="hljs-string">'Accept'</span>: <span class="hljs-string">"application/json"</span>,
    <span class="hljs-string">'Api-Token'</span>: <span class="hljs-string">"your_api_token"</span>
}

conn.request(<span class="hljs-string">"POST"</span>, <span class="hljs-string">"/api/send/your_inbox_id"</span>, payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode(<span class="hljs-string">"utf-8"</span>))
</code></pre>
<p>Once again, examine the API docs and <a target="_blank" href="https://api-docs.mailtrap.io/docs/mailtrap-api-docs/bcf61cdc1547e-send-email-early-access">this page</a>, in particular, to learn how to send API requests in Python (or other languages), send a sample request, and check out the sample response. </p>
<h2 id="heading-wrapping-up"><strong>Wrapping up</strong></h2>
<p>Python’s native methods are sufficient to test email-sending and run other functional tests. However, to check the spam score, the connection with external servers, or HTML/CSS, you’ll need a dedicated testing tool such as Mailtrap Email Testing. </p>
<p>If you want to learn more about email-sending and testing in Python, then check out our blog posts: </p>
<ul>
<li><p><a target="_blank" href="https://mailtrap.io/blog/python-send-email/">How to Send an Email in Python</a></p>
</li>
<li><p><a target="_blank" href="https://mailtrap.io/blog/python-send-email-gmail/">How to Send Emails in Python with Gmail</a></p>
</li>
<li><p><a target="_blank" href="https://mailtrap.io/blog/python-validate-email/">Python Options to Validate Email</a></p>
</li>
<li><p><a target="_blank" href="https://mailtrap.io/blog/python-mail-merge/">Mail Merge with Python</a></p>
</li>
<li><p><a target="_blank" href="https://mailtrap.io/blog/yagmail-tutorial/">How to Send an Email With Yagmail</a></p>
</li>
</ul>
<p>We’ve also covered sending emails in popular Python frameworks, such as <a target="_blank" href="https://mailtrap.io/blog/django-send-email/">Django</a> and <a target="_blank" href="https://mailtrap.io/blog/flask-email-sending/">Flask</a>. </p>
<p>Keep an eye on our blog as we publish more testing topics, such as how to test emails, email testing for beginners, email sandboxing, and others. </p>
<p>Don’t let Python’s snake crush your emails. Good luck!</p>
<p>Thank you for choosing this article! To discover more articles about <a target="_blank" href="https://mailtrap.io/blog/python-test-email/">testing emails using Python</a> follow Mailtrap blog!</p>
]]></content:encoded></item><item><title><![CDATA[How to Send Emails in Salesforce]]></title><description><![CDATA[As a robust CRM platform, Salesforce enables users to send all sorts of emails from its platform, from customer service emails to full-blown automated marketing campaigns. 
However, it can be a bit hard to figure out which method you should be using....]]></description><link>https://ketevanbostoganashvili.hashnode.dev/how-to-send-emails-in-salesforce</link><guid isPermaLink="true">https://ketevanbostoganashvili.hashnode.dev/how-to-send-emails-in-salesforce</guid><dc:creator><![CDATA[Ketevan Bostoganashvili]]></dc:creator><pubDate>Mon, 25 Dec 2023 09:02:02 GMT</pubDate><content:encoded><![CDATA[<p>As a robust CRM platform, Salesforce enables users to send all sorts of emails from its platform, from customer service emails to full-blown automated marketing campaigns. </p>
<p>However, it can be a bit hard to figure out which method you should be using. Should you send emails with Gmail or Yahoo? Should you use an Email Relay? Maybe you should build Flows and send automated emails? </p>
<p>In today’s comprehensive guide, we answer all these (and some other) questions and provide a step-by-step tutorial on sending emails from Salesforce. </p>
<h2 id="heading-email-sending-limits-in-salesforce"><strong>Email sending limits in Salesforce</strong></h2>
<p>Salesforce has several sending limitations based on the type of account and plan you’re using. </p>
<h3 id="heading-sending-limits-for-licensed-orgs"><strong>Sending limits for licensed orgs</strong></h3>
<p>Each licensed Salesforce org (i.e., orgs using the paid services) is allowed to send single emails to up to 5,000 external email addresses per day. The daily email limit is based on GMT and is renewed after midnight. By ‘external’ emails, Salesforce means any addresses not associated with a Contact, User, or Lead. The same limitation applies while sending mass or list emails. </p>
<p>For orgs registered before Spring 2019, the daily limit is enforced only when using Apex or Salesforce APIs with the exception of REST APIs. </p>
<p>For orgs registered in Spring 2019 or later, the daily limit also applies to emails sent through email alerts, simple email actions, Send Email actions, and REST API. </p>
<p>Additionally, each user in the org has their own hourly limits – they can send emails to up to 250 external recipients per hour. </p>
<p>Do keep in mind that each email address in the ‘To’, ‘Cc’, and ‘Bcc’ fields counts as a separate call while sending emails from Apex or API. So, if you had one address in each, it would count as three emails. </p>
<p>If you attempt to send emails after reaching this limit, you’ll encounter an error (SINGLE_EMAIL_LIMIT_EXCEEDED). </p>
<p>For more details, refer to the <a target="_blank" href="https://help.salesforce.com/s/articleView?id=sf.allocations_email_general.htm&amp;type=5">official Salesforce documentation</a>. </p>
<h3 id="heading-sending-limits-for-developer-and-trial-accounts"><strong>Sending limits for developer and trial accounts</strong></h3>
<p>Developer Edition and trial orgs have less generous daily limits. Each user can send emails to up to 50 recipients per day, with each email having a maximum of 15 recipients per day. Up to 10 recipients per day are allowed if you’re sending a List Email or Mass Email. </p>
<p>Also, you can have only 15 recipients per day in workflows. </p>
<p>These limits apply to user-to-user, Apex, workflow, mass, and single emails. </p>
<h2 id="heading-how-to-send-email-in-salesforce"><strong>How to send email in Salesforce</strong></h2>
<p>There are multiple email-sending configurations both in Salesforce Classic and Salesforce Lightning Experience. These configurations vary based on the email service provider or <a target="_blank" href="https://mailtrap.io/blog/email-infrastructure/">email infrastructure</a> you’re using. </p>
<h3 id="heading-how-to-send-emails-through-external-email-services"><strong>How to send emails through external email services</strong></h3>
<p>The easiest way to send emails from Salesforce is via Gmail or Microsoft 365 (labeled as Office 365 in the UI). You can switch on sending directly from the platform without having to go back and forth between your Gmail/Microsoft 365 and Salesforce accounts. </p>
<p>For all the instructions below, we’ll assume you’ve already set up Salesforce account. If not, go to <a target="_blank" href="https://help.salesforce.com/s/articleView?id=sf.allocations_email_general.htm&amp;type=5">salesforce.com</a>, choose the desired subscription, and fill out the registration form (or contact support, depending on the product you’re choosing). </p>
<p><em>The following steps apply to both Lightning Experience and Classic versions.</em> </p>
<p>Sign into your Salesforce account and navigate to <em>Setup</em>.</p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/Navigating-to-Setup-in-Salesforce.png" alt="Navigating to setup in Salesforce Lightning Experience " /></p>
<p><em>Navigating to Setup in Lightning Experience</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image.png" alt="Navigating to setup in Salesforce Classic" /></p>
<p><em>Navigating to Setup in Salesforce Classic</em> </p>
<p>In the <em>Quick Find</em> box, type in <em>Send through External Email Services</em>, hit enter, and click on the search result. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-7.png" alt="Send through External Email Services in Lightning Experience" /></p>
<p><em>Send through External Email Services in Lightning Experience</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-8.png" alt="Send through External Email Services in Salesforce Classic" /></p>
<p><em>Send through External Email Services in Salesforce Classic</em></p>
<p>Toggle either Gmail or Office 365, depending on which one you will use. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-46.png" alt="Configuring external email services in Lightning Experience " /></p>
<p><em>Configuring external email services in Lightning Experience</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-20.png" alt="Configuring external email services in Salesforce Classic " /></p>
<p><em>Configuring external email services in Salesforce Classic</em> </p>
<p>Then head over to the <em>Deliverability</em> under <em>Email (Email Administration in Classic)</em> in <em>Setup</em> and set <em>Access to Send Email (All Email Services)</em> to <em>All Email.</em> This will allow you to send all types of outbound emails. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-71.png" alt="Configuring deliverability in Lightning Experience" /></p>
<p><em>Configuring deliverability in Lightning Experience</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-80.png" alt="Configuring deliverability in Salesforce Classic" /></p>
<p><em>Configuring deliverability in Salesforce Classic</em></p>
<p>To configure email settings, go to <em>Settings</em> → My <em>Email Settings</em>. There, modify the sender name or set the email signature. You can also toggle between <em>Send through Salesforce</em> and <em>Send through Gmail/Office 365</em> features. Once you’re done, click <em>Save</em>. </p>
<p><em>Note: The ability to change the sender name is only available for Gmail users. If you’re using Office 365, you won’t be able to access this feature.</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/Configuring-email-settings-in-Lightning-Experience.png" alt="Configuring email settings in Salesforce Lightning Experience" /></p>
<p><em>Configuring email settings in Salesforce Lightning Experience</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-84.png" alt="Configuring email settings in Salesforce Classic" /></p>
<p><em>Configuring email settings in Salesforce Classic</em></p>
<p>Then, choose a contact to send an individual email or select a template. We go over different sending cases below. </p>
<p><em>Tip: Use Salesforce integration with Outlook and Gmail for seamless synchronization between the platforms. You’ll learn how to handle the setup</em> <a target="_blank" href="https://mailtrap.io/blog/salesforce-email-integration/"><em>here</em></a><em>.</em> </p>
<p>A couple of things to keep in mind: </p>
<ul>
<li><p>If you’re using Communities, you won’t be able to send emails with Gmail or Office 365. </p>
</li>
<li><p>This feature isn’t available for Einstein Activity Capture and Salesforce Inbox users either. </p>
</li>
<li><p>The emails you send through Gmail and Office 365 won’t be stored in Salesforce email logs, making it harder to track email delivery and deliverability. However, you can still access them in your email client or Gmail/Office 365 accounts. </p>
</li>
<li><p>You can’t send emails from organization-wide email addresses with Gmail or Office 365. They are usually sent through Salesforce. </p>
</li>
<li><p>Bounce management isn’t available with this feature. </p>
</li>
<li><p>List emails and emails sent by triggers and workflow rules are sent from Salesforce, not from Gmail or Office 365. </p>
</li>
</ul>
<h3 id="heading-how-to-send-emails-with-your-own-domain-and-salesforce"><strong>How to send emails with your own domain and Salesforce</strong></h3>
<p>To sidestep the limitations of <em>the Send through External Email Services</em> feature, you can send emails directly from Salesforce. However, this functionality only works if you have your own domain. You could use Gmail, Outlook, or Yahoo/AOL accounts, but you’d still have to get a custom domain. </p>
<p>If you send emails directly from Salesforce, you’ll be leveraging the email servers provided by the platform itself. </p>
<p>To enable it, head over to <em>Setup</em> → <em>Email</em> → <em>Deliverability</em>. Under the <em>Email Security Compliance (Emails from Salesforce or Email Relay Only)</em> tab, untick the box next to <em>Enable compliance with standard email security mechanisms</em> and <em>Enable Sender ID Compliance.</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-55.png" alt="Configuring deliverability settings in Lightning Experience " /></p>
<p><em>Configuring deliverability settings in Lightning Experience</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-54.png" alt="Configuring deliverability settings in Salesforce Classic " /></p>
<p><em>Configuring deliverability settings in Salesforce Classic</em> </p>
<p>Add Salesforce’s SPF record in the DNS records of your sending domain. For that, you’ll need access to the DNS control panel or the management console. The particular steps vary depending on your hosting provider so make sure you check their documentation for detailed instructions. Additional Salesforce-specific information is also available <a target="_blank" href="https://help.salesforce.com/s/articleView?id=000382664&amp;type=1">here</a>. </p>
<p>The final step is to set up Secure DKIM keys. This will ensure better <a target="_blank" href="https://mailtrap.io/blog/email-deliverability/">email deliverability</a> i.e., <a target="_blank" href="https://mailtrap.io/blog/salesforce-email-going-to-spam/">prevent email from going to spam</a>. </p>
<p>Go to <em>Setup</em> and type DKIM keys in the quick find box. Click <em>Create New Key.</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-26.png" alt="Secure DKIM Keys in Lightning Experience " /></p>
<p><em>Secure DKIM Keys in Lightning Experience</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-81.png" alt="Secure DKIM Keys in Salesforce Classic " /></p>
<p><em>Secure DKIM Keys in Salesforce Classic</em> </p>
<p>Choose the size of the RSA key. It’s recommended to use 2048-bit for more security, but you can use 1080-bit depending on the email recipients’ limitations. </p>
<p>Then enter unique values in the <em>Selector</em> and <em>Alternate Selector</em> fields. The latter will allow Salesforce to rotate your keys automatically. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-9.png" alt="Configuring DKIM Key details " /></p>
<p>The instructions on creating a DKIM key can be found <a target="_blank" href="https://dkim.org/#specifications">here</a>. Alternatively, read our <a target="_blank" href="https://mailtrap.io/blog/dkim">blog post</a> for more information or watch the video below. </p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/jy6YMzQZTz8">https://youtu.be/jy6YMzQZTz8</a></div>
<p> </p>
<p>Enter the domain name and configure the <em>Domain Match Pattern</em>. The pattern determines at what level the DKIM signature should be matched: domain, subdomain, or both. It should be a comma-separated list. For example, the pattern <a target="_blank" href="https://mailtrap.io/blog/salesforce-email-relay/">example.com</a>,*.<a target="_blank" href="https://mailtrap.io/blog/salesforce-email-relay/">example.com</a> will match at the domain and subdomain level. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-10.png" alt="Configuring DKIM key details " /></p>
<p>Click <em>Save</em>. At this point, Salesforce will publish your TXT records to DNS. Publication may take some time. Once it’s complete, you’ll be able to see your CNAME and alternate CNAME on the <em>DKIM Key Details</em> page. </p>
<p>Publish CNAME and alternate CNAME to your domain’s DNS and activate the DKIM keys from the <em>DKIM Key Details</em> page. </p>
<p>After that, you’ll be able to send emails from Salesforce Lightning Experience and Salesforce Classic with your own domain. </p>
<h3 id="heading-how-to-send-an-email-from-salesforce-with-a-third-party-smtp-server-and-email-relay"><strong>How to send an email from Salesforce with a third-party SMTP server and Email Relay</strong></h3>
<p>Salesforce also has an <a target="_blank" href="https://mailtrap.io/blog/salesforce-email-relay/">Email</a> <a target="_blank" href="https://mailtrap.io/blog/salesforce-email-relay/">Relay</a> feature that allows users to route their emails through the desired sending provider’s SMTP server or leverage any other SMTP server. </p>
<p>Opting for a reliable email service provider (ESP) is a good idea if you want to ensure high deliverability rates and send emails without volume restrictions. This is important whether you’re sending <a target="_blank" href="http://mailtrap.io/blog/email-marketing">email marketing</a> campaigns, mass emails, or vital transactional emails. </p>
<p>One such option is <a target="_blank" href="https://mailtrap.io/email-sending/">Mailtrap Email Sending</a> – an infrastructure with high deliverability rates offering both SMTP and Email API services. Thanks to its smooth SMTP integration, you can easily add it to your Salesforce platform. </p>
<p>Of course, you’ll need to create an account to get started. Go to the <a target="_blank" href="https://mailtrap.io/register/signup">sign-up page</a> and follow the simple steps to register and add your domain. More instructions are available in the <a target="_blank" href="https://help.mailtrap.io/article/110-get-started-mailtrap-email-sending">Getting Started Guide</a>. </p>
<p><em>Note: You should verify your domain to start sending emails.</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/Mailtrap-Domain-Verification.png" alt="Domain verification in Mailtrap Email Sending" /></p>
<p>Once your Email Sending account is up and running, go to the <em>Sending Domains</em> tab and click on your domain. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-13.png" alt="Sending domains in Mailtrap Email Sending " /></p>
<p>Navigate to the <em>API and SMTP</em> tab and select <em>SMTP</em> to reveal your SMTP credentials. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-86.png" alt="SMTP credentials in Mailtrap Email Sending " /></p>
<p>Now return to Salesforce and go to <em>Setup</em>  → <em>Email (under Administration)</em> → <em>Email Delivery Settings</em> → <em>Email Relays</em>.</p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-36.png" alt="Email Relay in Lightning Experience " /></p>
<p><em>Email Relay in Lightning Experience</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/Email-Relay-in-Salesforce-Classic.png" alt /></p>
<p><em>Email Relay in Salesforce Classic</em> </p>
<p>Click <em>Create Email Relay</em> and fill out the empty fields with Email Sending’s SMTP credentials as shown in the screenshot below: </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-12.png" alt="Configuring email relay " /></p>
<p>Tick the box next to <em>Enable SMTP Auth</em>, choose the authentication method (plain or login), and enter your SMTP username and password. Click <em>Save</em>. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-16.png" alt="Configuring email relay with Mailtrap Email Sending credentials " /></p>
<p>Then, navigate to <em>Email Domain Filters</em> and press <em>Create Email Domain Filter</em>, otherwise your relay won’t be activated. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/Email-Domain-Filter-In-Lightning-Experience.png" alt="Email Domain Filter in Lightning Experience" /></p>
<p><em>Email Domain Filter in Lightning Experience</em></p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-44.png" alt="Email Domain Filter in Salesforce Classic " /></p>
<p><em>Email Domain Filter in Salesforce Classic</em> </p>
<p>In the <em>Sender Domain</em> and <em>Recipient Domain</em> fields, enter <em>‘\</em>’<em> as the default wildcard. Tick the box next to </em>Active<em> and click </em>Save.* </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-18.png" alt="Activating domain filter " /></p>
<p>Now you can send emails with Mailtrap Email Sending’s SMTP server. In the email-sending options in the following sections, we’ll be using Mailtrap’s configuration. </p>
<p>After sending a test email, click <em>Verify Setup</em> in the <em>API and SMTP</em> tab in Email Sending and you’ll be all set. Then, analyze the performance of your emails with the Actionable Analytics feature with stats for categories and mailbox providers. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/Mailtrap-Stats-Page-dummy-screenshot.png" alt /></p>
<p><a target="_blank" href="https://mailtrap.io/register/signup"><strong>Start Sending with Mailtrap</strong></a></p>
<h2 id="heading-how-to-send-different-emails-in-salesforce-lightning-experience"><strong>How to send different emails in Salesforce Lightning Experience</strong></h2>
<p>In Lightning Experience, you have multiple options to send emails depending on your usage of the platform, including sending emails from a record, using merge fields with email templates, adding attachments, and sending emails from action. Let’s go over each use case. </p>
<h3 id="heading-sending-an-email-from-a-salesforce-record"><strong>Sending an email from a Salesforce record</strong></h3>
<p>Lightning Experience enables you to send emails directly from the record you’re on. You can use this option to contact existing customers or anyone in your system who has a valid email address. With this method, you can send rich or plain text emails using email templates or by compiling them manually. It’s also possible to add attachments, images, and links. </p>
<p>To get started, navigate to the record you want to send an email from. This can be an account, contact, lead, opportunity, case, or even a custom object.  </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-59.png" alt="Contacts list in Lightning Experience " /></p>
<p>Open the record and locate <em>Email</em> in the <em>Activity</em> tab. Press a downward arrow to choose email-sending options (Gmail or Outlook) or click on the <em>Email</em> button directly if your configurations are already set. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-75.png" alt="Sending emails in Salesforce with email button " /></p>
<p>A simple email editor will pop up. Insert a Lightning email template or create a custom email message. You’ll find more information about available templates and instructions on using email template builder <a target="_blank" href="https://mailtrap.io/blog/salesforce-email-templates/">here</a>. </p>
<p>To verify the details of the contact or account, you can scroll the record page without closing the editor. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-83.png" alt="Email editor in Lightning Experience " /></p>
<p>If you decide to use templates, add attachments or images, preview the email before sending it. That way, you’ll verify merge fields and ensure everything looks as expected. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-82.png" alt="Email preview" /></p>
<p>Once you’re done compiling the email, click <em>Send.</em> If you have Automatic Bcc enabled in <em>My Email Settings,</em> you’ll immediately receive a copy of the message to the indicated return address. The email log will also appear in the <em>Activity</em> tab of the record you sent an email to and in the related records (such as an account, for example). </p>
<p>To track the engagement (email open and click rates, conversions, bounce rates, etc.) and analyze the results of your campaigns, you should enable email tracking in your org. Go to <em>Setup → Activity Settings</em> and mark the checkbox next to <em>Enable Email Tracking.</em> Save the settings and you’ll be good to go. Read our <a target="_blank" href="https://mailtrap.io/blog/salesforce-email-tracking/">dedicated blog post</a> for more information on email tracking options in various Salesforce editions. </p>
<h3 id="heading-sending-emails-from-email-quick-actions"><strong>Sending emails from Email Quick Actions</strong></h3>
<p>Salesforce Lightning Experience streamlines the email-sending process for sales reps with the help of email quick actions. These allow you to create custom actions, predefine fields, and send emails without having to fill out field values manually. </p>
<p>If you don’t have email action, you can create it using the instructions below. If you already have one, a custom email quick action can be added for a specific account, opportunity, or business event. </p>
<p>Navigate to <em>Setup → Global Actions</em> and click the <em>New Action</em> button. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/Creating-a-custom-quick-action.png" alt="Creating a custom quick action " /></p>
<p>Choose <em>Send Email</em> as the <em>Action type</em> and <em>Email</em> as the <em>Standard Label Type.</em> Come up with a unique name for the action to avoid errors while executing API calls. Click <em>Save.</em>  </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/Entering-email-action-information-.png" alt="Configuring new action " /></p>
<p>A page layout editor window will appear. You can either accept the default configuration or adjust the properties for each field manually. Once you’re done, click <em>Save.</em> </p>
<p>Go to a record to check if the newly-created quick action is in place. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/Checking-quick-action.png" alt="Checking quick action " /></p>
<p>To automate processes even more, it’s possible to create predefined field values, such as To, Cc, or Bcc. </p>
<p>Navigate to <em>Global Actions</em> in <em>Setup</em> once again, open the email action you want to edit, and click <em>New</em> under <em>Predefined Field Values</em>. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-37.png" alt="Configuring predefined field values " /></p>
<p>Select <em>To, Cc,</em> or <em>Bcc</em> in the <em>Field Name</em> dropdown menu. Use the formula editor and <em>JUNCTIONIDLIST</em> function to associate the selected field with a Salesforce record. Click <em>Save.</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-52.png" alt="Creating new predefined field value for email " /></p>
<p><em>Note: JUNCTIONIDLIST is only necessary when using values with multiple IDs.</em> </p>
<p>That’s it. When you create a new email, the From (filled automatically by Salesforce) and To fields will be automatically defined. Then you can send emails as we did in the previous section.</p>
<h2 id="heading-how-to-send-emails-in-salesforce-classic"><strong>How to send emails in Salesforce Classic</strong></h2>
<p>Similar to Lightning Experience, Salesforce Classic also enables you to send a single email message from a particular record. </p>
<p>Open a specific record such as a contact, account, lead, opportunity, etc., and go to <em>Activity History.</em> </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-87.png" alt="Sending a single email message in Salesforce classic " /></p>
<p>Press the <em>Send an Email</em> button to open the email composer. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-11.png" alt="Salesforce send email " /></p>
<p>Choose between text and HTML editors and fill in the empty fields. Craft the email content manually or use one of the Salesforce Classic templates. You could also send emails with attachments from here. </p>
<p><img src="https://mailtrap.io/wp-content/uploads/2023/09/image-27.png" alt="Creating an email " /></p>
<p>Click <em>Send</em> and check the email in your inbox if you defined the Bcc field. </p>
<p>Remember that Email Composer takes note of the opt-outs. If you attempt to send an email to an unsubscribed user, you’ll see a warning message. However, this rule doesn’t apply to <em>Additional To, Cc,</em> and <em>Bcc</em> fields.</p>
<p>Thank you for reading this part of the article! Read full version in Mailtrap blog and discover more about <a target="_blank" href="https://mailtrap.io/blog/salesforce-send-email/">sending emails from salesforce</a>!</p>
]]></content:encoded></item><item><title><![CDATA[7 Email Preview Tools to Try Out Today]]></title><description><![CDATA[Email preview and rendering tools are an essential part of the workflow whether you’re a developer setting up email sending or a marketer crafting campaigns. 
For about a month, I tested the most popular options on the market to find the best email p...]]></description><link>https://ketevanbostoganashvili.hashnode.dev/7-email-preview-tools-to-try-out-today</link><guid isPermaLink="true">https://ketevanbostoganashvili.hashnode.dev/7-email-preview-tools-to-try-out-today</guid><dc:creator><![CDATA[Ketevan Bostoganashvili]]></dc:creator><pubDate>Fri, 08 Dec 2023 11:14:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033992173/b1a7e523-ab79-4547-b8a8-d3cda3519e9b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Email preview and rendering tools are an essential part of the workflow whether you’re a developer setting up email sending or a marketer crafting campaigns. </p>
<p>For about a month, I tested the most popular options on the market to find the best email preview tools. I split them into two segments: tools tailored to developers’ needs and tools created with marketers in mind. </p>
<p>Below I’ll share my findings and personal experience and add to that with valuable information gathered from other users. </p>
<h2 id="heading-selection-criteria-for-email-rendering-and-preview-tools"><strong>Selection criteria for email rendering and preview tools</strong></h2>
<p>Based on the role, requirements for email rendering and preview tools will vary significantly. So, I decided to compile different criteria for developers and marketers. </p>
<h3 id="heading-choosing-email-rendering-tools-for-software-engineers"><strong>Choosing email rendering tools for software engineers</strong></h3>
<p>To find the most functional email rendering tools for software developers, I used the following criteria:</p>
<ul>
<li><p><strong>A wide selection of email clients.</strong> This is an absolute must, as recipients view emails from various webmail and desktop clients. </p>
</li>
<li><p><strong>Ease of integration.</strong> The ability to integrate the tool into an email-sending script or project for accurate and comprehensive testing. </p>
</li>
<li><p><strong>Automated testing.</strong> With this feature, the checks will be performed on every email before they are sent. </p>
</li>
<li><p><strong>The ability to test attachments, broken links, and loading speed.</strong> </p>
</li>
<li><p><strong>HTML code checking.</strong> This ensures the code will be rendered accurately across email clients. </p>
</li>
<li><p><strong>Mail merge testing.</strong> The ability to verify merge fields and ensure personalized variables are correct. </p>
</li>
<li><p><strong>Sandbox environment.</strong> A virtual environment that will capture your test emails and prevent them from reaching your recipients. </p>
</li>
<li><p><strong>Spam checker.</strong> This will locate parts of your email (be it body, headers, or SMTP transaction info) that can be seen as spammy and harm your <a target="_blank" href="https://mailtrap.io/blog/email-deliverability/">email deliverability</a>. </p>
</li>
</ul>
<h3 id="heading-choosing-email-preview-software-for-marketers"><strong>Choosing email preview software for marketers</strong></h3>
<p>Unlike developers, marketers are mainly concerned with email design. So, I mainly focused on that in my selection criteria:</p>
<ul>
<li><p><strong>A wide selection of email clients.</strong> This one is common among the two groups. </p>
</li>
<li><p><strong>The ability to preview emails across different devices.</strong> Modern emails should be mobile, desktop, and tablet-optimized. </p>
</li>
<li><p><strong>Ease of integration.</strong> However, this time we’re looking for integration options that don’t require coding (plugins for Email Service Providers or CRM platforms, ready-made apps or platforms, etc.). </p>
</li>
<li><p><strong>Spam and blacklist checker.</strong> Ideally, this feature should check the email for common spam triggers, test it against popular <a target="_blank" href="https://mailtrap.io/blog/spam-filters/">spam filters</a>, and provide information about blacklisted IP addresses.  </p>
</li>
<li><p><strong>The ability to check the buttons and links.</strong> </p>
</li>
<li><p><strong>Value for money.</strong> We believe this criterion is more indicative of the products’ worth than affordability. It shows how many features are included in the set pricing and how many of them are limited to the higher-paying plans. </p>
</li>
</ul>
<h2 id="heading-best-email-preview-and-email-rendering-tools"><strong>Best email preview and email rendering tools</strong></h2>
<p>Before we dive into the reviews, let’s take a look at TL;DR comparison charts for the chosen email preview and email rendering tools. </p>
<h3 id="heading-email-rendering-tools-for-software-engineers-comparison-chart"><strong>Email rendering tools for software engineers: comparison chart</strong></h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Criteria</strong></td><td><strong>Mailtrap</strong></td><td><strong>Mailosaur</strong></td><td><strong>HTML Email Check</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Number of email clients</strong></td><td>Most email clients on the market</td><td>85</td><td>Approx. 45</td></tr>
<tr>
<td><strong>Integration options</strong></td><td>SMTP and API</td><td>SMTP and API</td><td>None (standalone platform)</td></tr>
<tr>
<td><strong>Automated testing</strong></td><td>Yes</td><td>Yes</td><td>No</td></tr>
<tr>
<td><strong>Attachments &amp; links testing</strong></td><td>Yes</td><td>Yes</td><td>Yes</td></tr>
<tr>
<td><strong>HTML code checker</strong></td><td>Yes</td><td>No</td><td>Yes</td></tr>
<tr>
<td><strong>Mail merge testing</strong></td><td>Yes</td><td>Yes</td><td>No</td></tr>
<tr>
<td><strong>Sandbox environment</strong></td><td>Yes</td><td>Yes</td><td>No</td></tr>
<tr>
<td><strong>Spam checker</strong></td><td>Yes</td><td>Yes</td><td>Yes</td></tr>
</tbody>
</table>
</div><h3 id="heading-email-preview-tools-for-marketers-comparison-chart"><strong>Email preview tools for marketers: comparison chart</strong></h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Criteria</td><td>Litmus</td><td>Email on Acid</td><td>Email Preview Services</td></tr>
</thead>
<tbody>
<tr>
<td><strong>Number of email clients</strong></td><td>More than 90</td><td>More than 90</td><td>More than 50</td></tr>
<tr>
<td><strong>Preview across different devices</strong></td><td>Yes</td><td>Yes</td><td>Yes</td></tr>
<tr>
<td><strong>Integration options</strong></td><td>Ready-to-use platform that integrates with ESPs, code editors, and collaboration tool. Also comes as a Chrome extension.</td><td>Ready-to-use platform</td><td>Ready-to-use platform and API integration</td></tr>
<tr>
<td><strong>Spam and blacklist checker</strong></td><td>Yes</td><td>Yes</td><td>Yes</td></tr>
<tr>
<td><strong>Buttons and links checking</strong></td><td>Yes</td><td>Yes</td><td>Link cheking</td></tr>
<tr>
<td><strong>Value for money</strong></td><td>1,000 email previews, 1 user, unlimited monitoring, 5,000 image impressions for $99/month</td><td>Unlimited email previews and projects, 1 user, email editor, and partial content checking for $99/month</td><td>Unlimited email previews, 5 inbox and spam tests, 1 user and simple email editor for $25/month</td></tr>
</tbody>
</table>
</div><p><em>Note: All prices are monthly rates. Most tools have discounts on annual subscriptions. Pricing is up-to-date at the time of publishing.</em> </p>
<h2 id="heading-3-email-rendering-tools-for-software-engineers-and-qas"><strong>3 Email rendering tools for software engineers and QAs</strong></h2>
<p>Now it’s finally time to share my findings. </p>
<p>To run the tests, I needed an HTML template. So, I went straight to <a target="_blank" href="https://mailtrap.io/email-sending/">Mailtrap Email Sending</a>’s <a target="_blank" href="https://help.mailtrap.io/article/105-email-templates">transactional email templates</a> feature. I found a great Welcome Email template created by one of my colleagues and got down to business. </p>
<h3 id="heading-mailtrap"><strong>Mailtrap</strong></h3>
<p><a target="_blank" href="https://mailtrap.io/">Mailtrap</a> is an email delivery platform that has both <a target="_blank" href="https://mailtrap.io/email-sending/">Email Sending</a> and <a target="_blank" href="https://mailtrap.io/email-sandbox/">Email Testing</a> solutions. For the purposes of this article, I’ll be focusing on Email Testing. </p>
<p>Email Testing is an Email Sandbox that captures all the SMTP traffic and provides a safe environment to analyze and debug your emails. </p>
<p>Creating an account and getting started is super straightforward. You just sign up, verify your email, and then you’ve got access to the platform. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033073031/6dac88e4-b26b-4558-b603-6886be76ae46.png" alt class="image--center mx-auto" /></p>
<p>I then went to the <em>Email Testing</em> tab, accessed <em>My Inbox</em>, tweaked the cURL with the HTML template, and sent the email. </p>
<p>Within seconds, I had the email in the virtual inbox. I didn’t have to use <a target="_blank" href="https://mailtrap.io/blog/email-for-testing/">dummy email addresses</a> or borrow real ones from my friends. Since the tool leverages the <a target="_blank" href="https://mailtrap.io/fake-smtp-server/">fake SMTP server</a>, sample emails were enough. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033104110/450e3852-7a1b-44a9-9cc4-0a49252d0272.png" alt class="image--center mx-auto" /></p>
<p>First, I checked mobile, desktop, and tablet previews to test how the email looks on these devices. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033131530/f925eb68-694d-4a2f-af07-118b4466f311.png" alt class="image--center mx-auto" /></p>
<p>Then, I navigated to the <em>HTML Source</em> tab. I found that the HTML contained elements that some email clients wouldn’t support. To examine the client support level further, I opened the <em>HTML Check</em> tab. </p>
<p>In its original form, the recipients who used Apple Mail on Desktop, Mobile, or the Web would have no trouble accessing my emails (the support was 100%). But the client support level was 77% for Gmail, 84% for Outlook, 71% for Yahoo! Mail, and 85% for other email clients. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033151876/7b934ae7-7048-468e-8b41-2a53b3226570.png" alt class="image--center mx-auto" /></p>
<p>One last step of the HTML check was to compare the text and HTML versions of the email. In this case, they matched. </p>
<p>I was quite impressed with the results I got from the <a target="_blank" href="https://mailtrap.io/html-email-checker/">HTML checker</a>. </p>
<p>I didn’t forget to click the buttons to ensure the links weren’t broken. </p>
<p>Finally, I headed over to the <em>Spam Analysis</em> tab. The score was 1.6, which meant I had nothing to worry about. I scrolled down to the Blacklist Report to verify that my IP wasn’t blacklisted. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033173825/55c8521f-feae-41a0-ba1d-fdb921a73a56.png" alt class="image--center mx-auto" /></p>
<p>What I found particularly interesting was that apart from the email template, you can also test email app load, email forwarding, BCC, and message headers. It’s possible to use Email Testing API with popular automation testing tools and software, including Selenium, Cucumber, Protractor, etc. </p>
<p><strong>Features</strong> </p>
<ul>
<li><p>HTML Check tab to check the emails for elements that won’t be supported (or be partially supported) by email clients </p>
</li>
<li><p>Spam Analysis to view the spam score and check the Blacklist report</p>
</li>
<li><p>SMTP and API integration options with code samples and official SDKs</p>
</li>
<li><p>A custom inbox email address with the ability to create aliases to simulate sending emails to recipients and test email app load (available starting from the Business plan) </p>
</li>
<li><p>Sandbox environment to avoid spamming recipients.</p>
</li>
<li><p>The ability to check the links and attachments.</p>
</li>
</ul>
<p><strong>Pros</strong> </p>
<ul>
<li><p>Can easily be integrated with the most popular programming languages and frameworks</p>
</li>
<li><p>The tool is well-documented, making it easier to get started </p>
</li>
<li><p>Tests can be performed in bulk </p>
</li>
<li><p>Makes it possible to not only analyze the template but also test email functionality</p>
</li>
</ul>
<p><strong>Cons</strong> </p>
<ul>
<li>Email previews are limited to mobile, desktop, and tablet. No client preview is available. </li>
</ul>
<p><strong>Pricing</strong> </p>
<p>Mailtrap Email Testing has a generous free tier with the ability to test up to 100 emails per month. The free tier includes 1 inbox, an inbox capacity of 50 emails, and a threshold of 5 emails per 10s. </p>
<p>Paid plans start from $14.99 (Individual plan) a month and provide access to advanced features and higher limits. You’ll find detailed pricing information <a target="_blank" href="https://mailtrap.io/pricing/">here</a>. </p>
<p>Access to customer support is equal for every user regardless of the plan they are using, while priority support is available starting from the Individual tier. </p>
<p><strong>What other users think (based on G2 and Capterra)</strong> </p>
<p>Mailtrap has 4.8 stars on <a target="_blank" href="https://www.g2.com/products/mailtrap/reviews">G2</a> and 5 stars on <a target="_blank" href="https://www.capterra.com/p/210463/Mailtrap/">Capterra</a>. </p>
<p>Most users found Email Testing easy to set up and use. They were satisfied with the available features and praised how supportive the customer service was. </p>
<p>Some users were displeased that inbox email addresses are limited to higher-paying plans, while others wished to see more storage capacity on free and lower-tier plans. </p>
<p><a target="_blank" href="https://mailtrap.io/register/signup"><strong>Try Mailtrap for Free</strong></a></p>
<h3 id="heading-mailosaur"><strong>Mailosaur</strong></h3>
<p>The second tool I tested was <a target="_blank" href="https://mailosaur.com/">Mailosaur</a>. It’s an end-to-end email testing solution very similar to Mailtrap Email Testing. </p>
<p>I created an account and started exploring the interface. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033234813/4ead244d-af0f-4389-9d59-d5a586c7bb77.png" alt class="image--center mx-auto" /></p>
<p>I clicked <em>Begin Email Testing</em> and I was taken to a step-by-step integration wizard. You have three options: </p>
<ul>
<li><p>Send an email to the generated email address (or its alias);</p>
</li>
<li><p>Integrate Mailosaur with SMTP;</p>
</li>
<li><p>Let the platform create a sample plain text email. </p>
</li>
</ul>
<p>For the initial test, I went with the first option as it seemed to be the fastest. I copied the email address and sent an HTML email to it. I clicked the <em>Inbox</em> in the left navigation panel and the email had already arrived. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033255214/803f85c5-87e8-453b-95eb-5dabad475e1a.png" alt class="image--center mx-auto" /></p>
<p>At this point, I was curious to see what elements of the email I could check. In the screenshot above, you can see a navigation panel on the right-hand side. Available options are <em>Links</em>, <em>Codes</em> (i.e. verification codes extracted from the email), <em>Attachments</em>, <em>HTML Source</em>, <em>API Response</em>, <em>Screenshots</em> (i.e. email client previews), <em>Deliverability Report</em>, and <em>Original</em>. </p>
<p>I played around with <em>Links</em>, <em>Codes</em>, and <em>Attachments</em>, and all of them yielded the expected results. </p>
<p>Then I opened the <em>HTML Source</em> tab which wasn’t what I expected it to be. The source code didn’t have any formatting, spacing, or indentations, making it hard to read and analyze. And unlike Mailtrap, it didn’t contain any information on supported/unsupported elements. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033272601/b590a19c-7bc0-4a5a-ba7d-caa697d09f85.png" alt class="image--center mx-auto" /></p>
<p>A nice surprise was the <em>API Response</em> tab which can potentially be quite useful to test how your API requests are performing. </p>
<p>The biggest jam of all was the <em>Screenshots</em> tab which enables you to generate screenshots for desired email clients. During the free trial, 85 email client previews were available (including dark mode and even iPhone 15 models). I played around with most of them and I must say, I was impressed. You can see some of the results in the image below. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033296138/4f3452fc-6195-4f17-8877-f92af88754f1.png" alt class="image--center mx-auto" /></p>
<p><em>Email previews from Mailosaur: (from left to right) Gmail App on iOS 14.2, Gmail App with Dark Mode on iOS 14.3, and iPhone 15</em></p>
<p>The next stop was the deliverability report. The platform scans your email to check if SPF, DKIM, and DMARC are configured properly for your domain. It also provides SpamAssassin results and checks the email for content indicators (‘spam triggers’). Mailosaur lists DNS records as well to help you detect issues and correct them</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033341789/70c43d02-3ff0-4df8-a370-66d6fa3ef3b0.png" alt class="image--center mx-auto" /></p>
<p>Finally, Original (EML) provides information about the email transaction and includes all the headers. </p>
<p>Another feature that I found quite useful was the ability to design and preview emails right within the platform. You simply copy and paste (or write from scratch) the HTML code and you immediately see what it looks like. As you edit the code, you can see the changes in design in live mode. </p>
<p>This feature includes email client screenshots as well. </p>
<p>I used more complex templates to test out this feature and I can safely say that Mailosaur really excels at previews. </p>
<p><strong>Features</strong> </p>
<ul>
<li><p>SMTP and API integration with SDKs for Playwright, Cypress, Node.js, Python, Java, .NET, Ruby, PHP, and Go</p>
</li>
<li><p>SMS Testing for companies that use SMS in addition to emails in their marketing communications</p>
</li>
<li><p>Sandbox environment</p>
</li>
<li><p>The ability to test multi-factor authentication</p>
</li>
<li><p>Email previews for 85 email clients</p>
</li>
<li><p>HTML code editor with real-time preview</p>
</li>
</ul>
<p><strong>Pros</strong> </p>
<ul>
<li><p>Easy integration and setup thanks to the step-by-step wizard and various integration options. </p>
</li>
<li><p>A wide selection of email clients. </p>
</li>
<li><p>The ability to create automated tests </p>
</li>
<li><p>In addition to basics, documentation covers common testing scenarios </p>
</li>
</ul>
<p><strong>Cons</strong> </p>
<ul>
<li>The HTML Source tab doesn’t provide useful information </li>
</ul>
<p><strong>Pricing</strong> </p>
<p>Mailosaur doesn’t have a free tier, but they do offer a 14-day free trial for all pricing tiers. The cheapest plan starts at $9 per month for 50 emails/day which can be upgraded up to 1,000 for an additional fee. </p>
<p>Mailosaur seems to have only annual billing at this point, which can be inconvenient for individuals or small teams. </p>
<p>Advanced features such as automatic forwarding, connecting via POP3, or SMS testing are available starting from the Business plan. </p>
<p><strong>What other users think (based on G2 and Capterra)</strong> </p>
<p>Mailosaur has a 4.9-star rating on <a target="_blank" href="https://www.g2.com/products/mailosaur/reviews">G2</a> and a 4.8-star rating on <a target="_blank" href="https://www.capterra.com/p/201911/Mailosaur/reviews/">Capterra</a>. </p>
<p>Most users reported that the platform was easy to integrate with modern QA automation tools, the UI was intuitive, and it was easy to search the messages. </p>
<p>The common complaint they had was the occasional inability of Mailosaur API to read emails and the per-user surcharge on pricing plans. </p>
<h3 id="heading-html-email-check"><strong>HTML Email Check</strong></h3>
<p><a target="_blank" href="https://www.htmlemailcheck.com/">HTML Email Check</a> is a bit different from the previous tools. Instead of being a ‘traditional’ HTML email preview tool, it’s more like a markup validation software. While it does have the visual testing feature, it’s built to analyze the HTML, XHTML, and CSS in your code. </p>
<p>And when I say it’s an HTML code checker, I mean it. This feature is free, and you don’t even have to create an account. </p>
<p>All you have to do is paste your HTML code into the dedicated field, click <em>Check Code</em>, and you’ll immediately see a list of issues in your script. This list also includes the number of lines that were affected, as well as possible fixes. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033372938/ca5483d7-5f1f-4efe-bc01-08daf9e72d12.png" alt class="image--center mx-auto" /></p>
<p>As I scrolled down and examined the recommendations closely, I noticed that the check results included information about the affected email clients. So, some parts of my HTML code (&lt;strong&gt; and &lt;div&gt; tags) wouldn’t be supported by Gmail, Microsoft Outlook, and Yahoo! Mail. </p>
<p>My email had way more issues when it came to CSS. And I had a whole list of email clients along with short explanations. I found these short explanations useful, particularly for junior developers learning HTML and CSS. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033402138/e68f8b57-eb96-408c-b19f-4c718810dfde.png" alt class="image--center mx-auto" /></p>
<p>The rest of the tests and features are paid. Once you upgrade to one of the plans, you get access to font, image, and link validation, as well as spam checker, visual tester, dark mode, accessibility validation, etc. </p>
<p>Accessibility validation is an important feature and I was very happy to see it on this platform. It checks your code for alt text and tags, provides recommendations on font size and readability, and validates dark mode. And all those tests are client-specific. </p>
<p>What’s not client-specific is the visual tester. I was able to test the email template on desktop, tablet, and mobile devices in portrait and landscape modes. But I couldn’t preview them in email clients the way I did with Mailosaur. </p>
<p>Overall, I really enjoyed using HTML Email Check as it has a minimal learning curve. In terms of creating an error-free HTML code, this tool is very hard to beat. </p>
<p><strong>Features</strong> </p>
<ul>
<li><p>Accessibility and dark mode validation </p>
</li>
<li><p>Comprehensive HTML and CSS checker </p>
</li>
<li><p>Spam checker </p>
</li>
<li><p>The ability to send test emails to real inboxes </p>
</li>
</ul>
<p><strong>Pros</strong></p>
<ul>
<li><p>Runs validation checks against the most popular email clients</p>
</li>
<li><p>Has an HTML email previewer </p>
</li>
<li><p>Can be used in conjunction with your email service provider (ESP) </p>
</li>
<li><p>Very easy to get started and use </p>
</li>
<li><p>Provides recommendations to debug your HTML code </p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>The free email checker is limited in functionality </p>
</li>
<li><p>Message preview is device-based </p>
</li>
</ul>
<p><strong>Pricing</strong></p>
<p>HTML Email Check has three pricing tiers. The Standard plan costs $23.95 a month and provides access to core validation features. The Business plan will cost you $35.95 a month, but you’ll be able to use a spam checker, visual tester, email sending for test emails, and validation expert. </p>
<p>There’s also an Enterprise plan for $59.95 a month with access to accessibility, dark mode, and mobile validation, a developer checklist, 24/7 priority support, and a visual tester inspector.</p>
<p>HTML Email Check doesn’t have a free trial for the paid plans, but it does offer limited free email testing features.</p>
<p><strong>What other users think (based on G2 and Capterra)</strong> </p>
<p>At the time of writing, HTML Email Check doesn’t have any reviews on G2 or Capterra. </p>
<h2 id="heading-4-email-preview-tools-for-marketers"><strong>4 Email preview tools for marketers</strong></h2>
<p>Below I’ll be diving into 4 email preview tools for marketers that proved to be most reliable and effective.</p>
<h3 id="heading-litmus"><strong>Litmus</strong></h3>
<p>Litmus has two tools for previewing emails: <a target="_blank" href="https://putsmail.com/">PutsMail</a> (the free option) and <a target="_blank" href="https://www.litmus.com/">Litmus</a> itself (the paid version). </p>
<p>The free email preview tool is quite limited. You can use it to inline CSS or send test emails to sample email addresses you own, but I didn’t find it usable, especially compared to Litmus itself. </p>
<p>So, in this review, I’ll be concentrating on Litmus. </p>
<p>Getting started with this tool is quite easy – you just create an account, activate your free trial or subscription by entering your card details, and you’re ready to use the features right away. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033435070/4657a6db-af5b-4a0e-b6f5-5cef46e6abf6.png" alt class="image--center mx-auto" /></p>
<p>To start testing, you can use one of their templates or build your own email from scratch. I chose the second option as I wanted to test a particular HTML email. This takes you to a builder, which previews the email as you enter the script. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033460887/b686fa78-eb0c-40c8-b052-1932cf03f29f.png" alt class="image--center mx-auto" /></p>
<p>The preview options are quite extensive and include dark mode, mobile and desktop views, image toggle, and different visual impairment options. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033478594/2da28938-3ea8-499d-9783-3b6f707521f0.png" alt class="image--center mx-auto" /></p>
<p>As expected, the <em>Preview</em> tab shows email previews for various email clients. But the information in the <em>QA Checks</em> tab is way more interesting. </p>
<p>Litmus shows your template’s preview text example and provides recommendations. For example, my template lacked preview text, so Litmus recommended adding it as the first element in the body and keeping the preview text length above 90 characters. </p>
<p><em>Note: Email preview text (or preheader text) is the short ‘description’ shown under the subject line in most email clients.</em> </p>
<p>QA checks also included accessibility and loading speed tests. These were initial tests that allow you to improve your template as you’re building it. </p>
<p>As you move to the <em>Previews &amp; QA</em> tab, you can see those test results (and some additional tests) in more detail. </p>
<p>Apart from the mentioned components, Litmus will check the subject line, links, and tracking, and run the spam tests. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033498007/152a6cf3-f228-4045-99c2-8be9438591ec.png" alt class="image--center mx-auto" /></p>
<p>Email Guardian is a great addition to these features. It monitors major email clients and notifies you of any important changes. This way, you can continuously improve selected templates to avoid issues with deliverability, accessibility, or rendering. </p>
<p>What I liked the most was the ability to sync Litmus with your ESP to test email marketing campaigns automatically. Integration options include HubSpot, Mailchimp, Campaign Monitor, Salesforce Marketing Cloud, and others. </p>
<p>On the downside, the platform can get a bit slow at times, especially while loading previews. </p>
<p><strong>Features</strong> </p>
<ul>
<li><p>Integration with popular ESPs to test templates automatically </p>
</li>
<li><p>Email Guardian that monitors email clients</p>
</li>
<li><p>Real-time preview for more than 90 email clients </p>
</li>
<li><p>Code and drag-and-drop template builder </p>
</li>
<li><p>Extensive accessibility tests for various visual disabilities </p>
</li>
</ul>
<p><strong>Pros</strong></p>
<ul>
<li><p>Easy-to-use, intuitive UI </p>
</li>
<li><p>No coding is required (unless you’re building an HTML template script from scratch)</p>
</li>
<li><p>Integration with collaboration tools </p>
</li>
<li><p>An email testing checklist for building perfect emails </p>
</li>
</ul>
<p><strong>Cons</strong></p>
<ul>
<li><p>ESP and code editor integrations are available only for higher-paying plans </p>
</li>
<li><p>Previews may take a while to load </p>
</li>
<li><p>A bit pricey compared to its competitors </p>
</li>
</ul>
<p><strong>Pricing</strong> </p>
<p>Litmus has three pricing tiers: Litmus Basic, Litmus Plus, and Litmus Enterprise. </p>
<p>Litmus Basic starts at $99 a month and includes all the basic features you’d need. Litmus Plus will cost you $199 a month but it will give you access to spam tests, ESP integrations, code editor integrations, etc. </p>
<p>For Litmus Enterprise, you’ll need to request a custom quote. </p>
<p>Basic and Plus plans have a 7-day free trial for a detailed test run. </p>
<p><strong>What other users think (based on G2 and Capterra)</strong> </p>
<p>Litmus has 4.7 stars on <a target="_blank" href="https://www.capterra.com/p/178360/Litmus/reviews/">Capterra</a> and 4.6 stars on <a target="_blank" href="https://www.g2.com/products/litmus/reviews">G2</a>. </p>
<p>Most users enjoyed the variety of features and the ease of using the platform. Some downsides they emphasized were the loading time of previews, expensive pricing, and hard-to-set-up analytics. </p>
<h3 id="heading-email-on-acid"><strong>Email on Acid</strong></h3>
<p>Similar to Litmus, <a target="_blank" href="https://www.emailonacid.com/">Email on Acid</a> is an email builder and preview testing tool in one. It provides two types of testing: Email Testing which tests your template and Campaign Precheck which runs tests based on a predefined checklist. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033524593/f26ea4d1-0de7-4275-9bc2-3a762460d636.png" alt class="image--center mx-auto" /></p>
<p>Email Testing provides previews for more than 90 email clients, runs deliverability tests by checking feedback filters and authentication protocols, and validates URLs. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033550011/85c86691-6f67-4763-96ca-14483625e389.png" alt class="image--center mx-auto" /></p>
<p>So, the results of Email Testing were nothing out of the ordinary and were similar to the info we received from other tools. </p>
<p>Where Email on Acid stands out is the Campaign Precheck. Initially, I didn’t think it would be much different from Email Testing. But Campaign Precheck is way more comprehensive and allows you to refine every aspect of your email before it gets to recipients. </p>
<p>To use this feature, you can either leverage Email on Acid’s default workflow or create your own. Since I wanted to see what the tool was capable of, I chose the recommended workflow. </p>
<p>Here’s what it does: </p>
<ul>
<li><p>Allows you to set the sender name, email subject line, and preheader text while previewing them on mobile, desktop, and webmail; </p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033580564/4e51a53f-bbb0-41f2-9a78-f288ed2ff4e2.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Helps you optimize the accessibility of the email through a step-by-step process and provides explanations for each step. I was able to hear the difference between screen reader behaviors with and without pre-defined language. Any issues can easily be fixed by clicking a button;</li>
</ul>
</li>
</ul>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033601389/0aa954ba-7a0f-43e8-82e5-fec6dca6188d.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Checks the links and provides an option to add UTM parameters to get more accurate results when you analyze the campaign in Google Analytics;</p>
</li>
<li><p>Optimizes images and other media;</p>
</li>
<li><p>Checks the email content for spelling errors; </p>
</li>
<li><p>Checks the email for blocklisted domains; </p>
</li>
<li><p>Runs the spam test on the subject line. While I like this feature, it can take a while to complete;</p>
</li>
<li><p>Shows you previews for selected email clients;</p>
</li>
<li><p>Provides a Precheck summary and allows you to see the changes made to the code. </p>
</li>
</ul>
<p>    Email on Acid has an email editor with templates. However, the designs seemed a bit outdated. </p>
<p>    It’s also possible to set up email analytics but I haven’t given it a fair try as my focus was to test the email testing portion of the tool. The analytics feature allows you to track open rates, the effectiveness of call-to-action (CTA) buttons, click-through (CTR) rates, and other important metrics.</p>
<p>    <strong>Features</strong> </p>
<ul>
<li><p>Multiple testing options to refine email templates before sending them to an email list </p>
</li>
<li><p>A wide selection of email clients</p>
</li>
<li><p>A step-by-step wizard that adjusts the code automatically without the users having to code themselves</p>
</li>
<li><p>The ability to send test emails from ESP, Email on Acid platform, or a selected SMTP server for deliverability checks</p>
</li>
</ul>
<p>    <strong>Pros</strong></p>
<ul>
<li><p>Minimal learning curve </p>
</li>
<li><p>Easy to optimize the template and see the reason behind each modification </p>
</li>
<li><p>Code editor with snippets and live preview</p>
</li>
<li><p>Comprehensive tests </p>
</li>
</ul>
<p>    <strong>Cons</strong></p>
<ul>
<li><p>Lacks regular and dark mode previews for the Gmail app on iOS and Android </p>
</li>
<li><p>Spam tests take a while to load </p>
</li>
<li><p>Lacks information on why the email failed the spam filter test </p>
</li>
</ul>
<p>    <strong>Pricing</strong></p>
<p>    Email on Acid has four pricing tiers: The Basics, Premium, Professional, and Enterprise. </p>
<p>    The Basics costs $99/month and includes unlimited previews and projects, 1 user, partial content checking, and an email editor. Premium costs $179/month and provides access to full content checking, deliverability tests, 3 users, and email analytics for 500k opens/month. </p>
<p>    Professional costs $599/month for 10 users, custom user permissions, dedicated support representative, and email analytics for 1.5M opens/month. </p>
<p>    You should get a custom quote to use an Enterprise plan. </p>
<p>    There’s a 7-day free trial for all paid plans. </p>
<p>    <strong>What other users think (based on G2 and Capterra)</strong> </p>
<p>    Email on Acid has 4.5 stars on <a target="_blank" href="https://www.g2.com/products/email-on-acid/reviews">G2</a> and 4.4 starts on <a target="_blank" href="https://www.capterra.com/p/174836/Email-on-Acid/reviews/">Capterra</a>. </p>
<p>    Most users enjoy the results they get from Campaign Precheck tests, the fact that they don’t have to code to optimize the template, and how easy it is to use the platform. </p>
<p>    Some disadvantages users highlighted were the lack of certain important clients and the occasional inaccuracy of email previews. </p>
<h3 id="heading-email-preview-services-formerly-previewmyemail"><strong>Email Preview Services (formerly PreviewMyEmail)</strong></h3>
<p>    The third tool I chose for this list is <a target="_blank" href="https://emailpreviewservices.com/en">Email Preview Services</a>, formerly known as PreviewMyEmail. It’s suitable for developers and marketers. </p>
<p>    For developers, it has a white-label API that can be used to preview email templates from any programming language. However, this feature is only available to enterprise users. That’s why I decided to include it here. </p>
<p>    There are two ways of accessing inbox preview: by sending an email to the inbox address or inserting a template manually.</p>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033650524/87ea411f-0ded-4fd3-b5ed-307d57cff041.png" alt class="image--center mx-auto" /></p>
<p>    First, I opened the <em>Preview</em> tab, clicked <em>Create a new test</em>, and added my template manually. There’s a list of email clients and you can easily toggle between them if needed. I clicked <em>Start Test</em> and the previews started loading. I’d say the loading time was average. </p>
<p>    While I liked the quality of the screenshots, client previews certainly lacked Android options and modern iPhone devices. Web browser and desktop email clients were more diverse, though. </p>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033679504/2a85cd77-5a64-4893-950d-5217bc803872.png" alt class="image--center mx-auto" /></p>
<p>    Then I sent an email to an inbox email address and the results were exactly the same. </p>
<p>    There’s also an option to create, store, download (HTML), or test templates right on the platform. </p>
<p>    Finally, I ran the spam test. This test checks the sender score, authentication protocols, blacklists, links, images, and HTML code.  </p>
<p>    Overall, Email Preview Services provides high-quality previews at an affordable price. While it may lack the advanced features that Email on Acid and Litmus have, it still delivers great value for money. </p>
<p>    <strong>Features</strong></p>
<ul>
<li><p>Previews from around 50 email clients </p>
</li>
<li><p>Spam and infrastructure checks</p>
</li>
<li><p>Drag-and-drop email editor</p>
</li>
<li><p>Analytics feature that provides data on which clients recipients use, unique total opens, geolocation, email address activity log, etc. </p>
</li>
</ul>
<p>    <strong>Pros</strong></p>
<ul>
<li><p>High-quality preview screenshots </p>
</li>
<li><p>Affordable pricing </p>
</li>
<li><p>Straightforward platform and testing workflow </p>
</li>
</ul>
<p>    <strong>Cons</strong> </p>
<ul>
<li><p>Email client previews lack modern devices and operating systems </p>
</li>
<li><p>Content and HTML checks could be more comprehensive </p>
</li>
</ul>
<p>    <strong>Pricing</strong></p>
<p>    Email Preview Services has four pricing plans: Standard, Business, Professional, and Enterprise. </p>
<p>    If you choose the Standard plan, you’ll pay $25 a month for unlimited previews, 5 email spam and inbox tests, a simple editor, and 1 user. The Business plan is available for $45 a month and provides access to analytics, an advanced editor, 25 spam and inbox tests, and 1 user. </p>
<p>    For more seats, analytics, and spam tests, you’ll have to opt either for a Professional ($160/month) or Enterprise ($399/month) plan. </p>
<p>    A 7-day free trial is available for all paid plans. </p>
<p>    <strong>What other users think (based on G2 and Capterra)</strong> </p>
<p>    At the time of writing, Email Preview Services doesn’t have reviews on G2 and Capterra. </p>
<h3 id="heading-sendforensics"><strong>SendForensics</strong></h3>
<p>    <a target="_blank" href="https://www.sendforensics.com/">SendForensics</a> is an email deliverability testing tool that allows you to preview and test email campaigns. </p>
<p>    After signing up, you’re prompted to send an email to a specific email address. </p>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033719433/7e36f2f5-aac0-4f73-86b4-bed43deb443b.png" alt class="image--center mx-auto" /></p>
<p>    Within seconds, you’ll see it on the SendForensics platform. At that point, the email has already been analyzed and you can access the results right away. </p>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033766241/78019245-acee-442a-8d36-55ac11bbd40a.png" alt class="image--center mx-auto" /></p>
<p>    As you press your sending domain, you’re taken to a <em>Snapshot</em> that contains the overall results of the analysis. You can see deliverability score, infrastructure analysis, and content analysis. </p>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033803796/0939b711-480f-4802-b23e-f4e1cba804cf.png" alt class="image--center mx-auto" /></p>
<p>    The <em>Content</em> tab highlights problematic elements of your email content. It scans your email for spam triggers that can land you in a spam folder. In this tab, you’ll find potential issues with HTML code, link validation results, and improper data collection practices, if any. </p>
<p>    I adjusted the template according to the platform’s recommendations and ran another test. That’s when I noticed that their content-checking feature wasn’t as robust as I expected. The recommendations can be ambiguous and unusable at times. </p>
<p>    The good thing is, there’s an explanation for each recommendation. So, you can use your own expertise to filter out the results. </p>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033830118/4c2c6e5b-48b9-4729-ab46-a1a4c2ea9b85.png" alt class="image--center mx-auto" /></p>
<p>    In terms of infrastructure, SendForensics checked if my IP was blacklisted and scanned my SPF, DKIM, and DMARC records. This is quite useful, especially if you’re trying to improve the template to ensure good deliverability rates. For more accurate and comprehensive checks, it’s possible to add an ESP plugin to SendForensics. </p>
<p>    There’s also an option to check cookie forensics and legal compliance. This includes checking whether the email has an unsubscribe link in it. </p>
<p>    The last tab is <em>Previews</em> which shows you how your email will look in different email clients. The results are actual screenshots, not simulations. This will help you avoid improper rendering as you send the campaigns to recipients. </p>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702033858894/5f13b879-720c-44d8-ae61-8aad7073b41c.png" alt class="image--center mx-auto" /></p>
<p>    <em>Email Previews for Apple Mail (Desktop), AOL (Webmail), and Gmail (Webmail)</em></p>
<p>    <strong>Features</strong> </p>
<ul>
<li><p>Deliverability analysis</p>
</li>
<li><p>Content checks</p>
</li>
<li><p>Email preview screenshots</p>
</li>
<li><p>ESP plugins </p>
</li>
<li><p>Customizable domain settings for accurate tests </p>
</li>
</ul>
<p>    <strong>Pros</strong></p>
<ul>
<li><p>Recommendations that are easy to understand and implement</p>
</li>
<li><p>Comprehensive deliverability checks</p>
</li>
<li><p>Ready-to-use platform </p>
</li>
<li><p>Integration with a third-party ESP</p>
</li>
<li><p>Affordable compared to other preview tools</p>
</li>
</ul>
<p>    <strong>Cons</strong></p>
<ul>
<li><p>You have to send emails to SendForensics over and over again to access analysis after modifying the template</p>
</li>
<li><p>Content improvement recommendations aren’t always accurate</p>
</li>
</ul>
<p>    <strong>Pricing</strong></p>
<p>    SendForensics has four pricing plans: Brand at $49/month, Company at $79/month, Agency at $199, and Enterprise at $349. </p>
<p>    The pricing plans aren’t feature-based, which means that most of the features are similar across the tiers. What differs is the number of domains, users, and DMARC reports per month. </p>
<p>    The cheapest plan (Brand) has a 14-day free trial. A free plan isn’t available. </p>
<p>    <strong>What other users think (based on G2 and Capterra)</strong> </p>
<p>    SendForensics has 3.8 stars on <a target="_blank" href="https://www.g2.com/products/sendforensics/reviews">G2</a> and 4.3 stars on <a target="_blank" href="https://www.capterra.com/p/163121/SendForensics/#reviews">Capterra</a>. </p>
<p>    This tool isn’t as popular as the others, so the rating is based on 6 reviews in total. </p>
<p>    Most users liked the deliverability checks, value for money, and the ability to run unlimited tests. </p>
<p>    Just like me, others also noticed that the content checks need a bit of improvement to be more accurate. </p>
<h2 id="heading-key-takeaways"><strong>Key Takeaways</strong></h2>
<p>    So, to conclude, here are some key takeaways from my research: </p>
<ol>
<li><p>Finding decent email rendering and email preview tools isn’t easy, especially for developers</p>
</li>
<li><p>Pricing tends to be on the higher side for email preview tools created for marketers</p>
</li>
<li><p>There’s no such thing as a free email preview tool, but there certainly are free tiers with limited features and previews </p>
</li>
<li><p>Most email marketing platforms will allow you to preview emails before sending them and some will even have email client previews. Such platforms include Mailchimp, GetResponse, Constant Contact, and others.</p>
</li>
<li><p>Email marketing platforms won’t provide comprehensive previews and tests. For that, you will need to invest in a dedicated tool.</p>
</li>
</ol>
<p>    If you’re interested in email client testing and email testing in general, check out the recommended reads: </p>
<ul>
<li><p><a target="_blank" href="https://blog.mailtrap.io/email-testing-checklist/">Email Testing Checklist</a></p>
</li>
<li><p><a target="_blank" href="https://blog.mailtrap.io/test-email-deliverability/">The Best Email Deliverability Testing Tools</a></p>
</li>
<li><p><a target="_blank" href="https://mailtrap.io/blog/email-client-testing/">Email Client Testing Explained</a></p>
</li>
</ul>
<p>    Keep an eye on our blog as we’ll be covering even more testing topics in the upcoming months.</p>
<p>    Good luck and preview away!</p>
<p>Thank you for reading this email! Find more <a target="_blank" href="https://mailtrap.io/blog/email-preview/">email rendering tools</a> in Mailtrap blog!</p>
]]></content:encoded></item></channel></rss>