- mailgun 2017-03-19T16:58:15+01:00 https://fadeit.dk/blog/tag/mailgun.html Digital Ocean DNS setup for Mailgun 2015-11-03T11:22:30+01:00 https://fadeit.dk/blog /2015/11/03/mailgun-dns-setup-digital-ocean <p>When setting up Mailgun (MG) &amp; Digital Ocean (DO) I ran into unexpected complications. Unfortunately DNS configuration feedback l<font size="4" style="position:relative; top:2px;">&infin;</font>p takes long time (as DNS settings propagate), so it ended taking me some days just to try couple configurations. There are some misleading tutorials out there as-well, so hopefully I can clear it once for all.</p> <p>So the first gotcha with DO is that the domain name is automatically added to the DNS records, therefore if MG setting says <code class="highlighter-rouge">email.fadeit.dk</code>, then that means only <code class="highlighter-rouge">email</code> should be entered in DO:</p> <p><img src="/blog/assets/mailgun-dns-setup-digital-ocean/cname.jpg" alt="Domain is automatically appended" /></p> <p>Second gotcha requires us to wrap TXT record value in quotes:</p> <p><img src="/blog/assets/mailgun-dns-setup-digital-ocean/quotes.jpg" alt="TXT records need to be wrapped in quotes" /></p> <p>So-far we’ve looked at the setup as it is for primary domain, however MG suggests configuring a subdomain instead. While it is possible to set the TXT &amp; CNAME records for a subdomain, MX records can not be configured for a subdomain that way. Fortunately there is a (non-obvious) solution - subdomain should be added as a domain in DO panel:</p> <p><img src="/blog/assets/mailgun-dns-setup-digital-ocean/subdomain.jpg" alt="Subdomain should be added as a domain" /></p> <p>Now we can configure MX records for that subdomain, and while at it…move other records to the subdomain configuration aswell. Keep in mind that now DO appends entire subdomain to TXT &amp; CNAME records:</p> <p><img src="/blog/assets/mailgun-dns-setup-digital-ocean/conf.jpg" alt="Subdomain should be added as a domain" /></p> Python logging handler for Mailgun 2015-10-12T13:25:30+02:00 https://fadeit.dk/blog /2015/10/12/mailgun-python-log-handler <p>Yet another reason to love python is the wonderful logging API provided by a standard library. Having a decent logger provided by the language saves developers time from integrating with some third-party library, but most importantly it contributes to a clean system where all modules use the same logger. Out of the box, there is a <a href="https://docs.python.org/3/library/logging.handlers.html">handler</a> for almost any typical use-case, but the best feature is the option to create your own with relative ease. So-far we’ve been using <a href="https://docs.python.org/3/library/logging.handlers.html#smtphandler">SMTPHandler</a>, but since moving to <a href="https://www.mailgun.com/">Mailgun</a>, I decided to experiment with a custom handler to submit logs via their API instead. I’d like to mention that creating a custom logging handler is not a requirement, it is still possible to use their SMTP server with SMTP handler. To get started, we need to extend Handler baseclass and override emit method to make a POST request.</p> <div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">logging</span> <span class="kn">import</span> <span class="nn">requests</span> <span class="k">class</span> <span class="nc">MailgunHandler</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Handler</span><span class="p">):</span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">api_url</span><span class="p">,</span> <span class="n">api_key</span><span class="p">,</span> <span class="n">sender</span><span class="p">,</span> <span class="n">recipients</span><span class="p">,</span> <span class="n">subject</span><span class="p">):</span> <span class="c"># run the regular Handler __init__</span> <span class="n">logging</span><span class="o">.</span><span class="n">Handler</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">api_url</span> <span class="o">=</span> <span class="n">api_url</span> <span class="bp">self</span><span class="o">.</span><span class="n">api_key</span> <span class="o">=</span> <span class="n">api_key</span> <span class="bp">self</span><span class="o">.</span><span class="n">sender</span> <span class="o">=</span> <span class="n">sender</span> <span class="bp">self</span><span class="o">.</span><span class="n">recipients</span> <span class="o">=</span> <span class="n">recipients</span> <span class="bp">self</span><span class="o">.</span><span class="n">subject</span> <span class="o">=</span> <span class="n">subject</span> <span class="k">def</span> <span class="nf">emit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span> <span class="c"># record.message is the log message</span> <span class="k">for</span> <span class="n">recipient</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">recipients</span><span class="p">:</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="s">"from"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">sender</span><span class="p">,</span> <span class="s">"to"</span><span class="p">:</span> <span class="n">recipient</span><span class="p">,</span> <span class="s">"subject"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">subject</span><span class="p">,</span> <span class="s">"text"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">record</span><span class="p">)</span> <span class="p">}</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">api_url</span><span class="p">,</span> <span class="n">auth</span><span class="o">=</span><span class="p">(</span><span class="s">"api"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">api_key</span><span class="p">),</span> <span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span> </code></pre> </div> <p>I have created a simple flask application that registers the handler and also implemented a route that triggers an error to test it out.</p> <div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">logging</span> <span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> <span class="kn">from</span> <span class="nn">mailgun_handler</span> <span class="kn">import</span> <span class="n">MailgunHandler</span> <span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> <span class="c"># Setup logging handler</span> <span class="n">mail_handler</span> <span class="o">=</span> <span class="n">MailgunHandler</span><span class="p">(</span> <span class="n">api_url</span><span class="o">=</span><span class="s">'https://api.mailgun.net/v3/fadeit.dk/messages'</span><span class="p">,</span> <span class="n">api_key</span><span class="o">=</span><span class="s">'secret'</span><span class="p">,</span> <span class="n">sender</span><span class="o">=</span><span class="s">'noreply@fadeit.dk'</span><span class="p">,</span> <span class="n">recipients</span><span class="o">=</span><span class="p">[</span><span class="s">'ss@fadeit.dk'</span><span class="p">,</span> <span class="s">'ja@fadeit.dk'</span><span class="p">],</span> <span class="n">subject</span><span class="o">=</span><span class="s">'Application error!'</span> <span class="p">)</span> <span class="n">mail_handler</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">)</span> <span class="n">mail_handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s">''' Message type: </span><span class="si">%(levelname)</span><span class="s">s Location: </span><span class="si">%(pathname)</span><span class="s">s:</span><span class="si">%(lineno)</span><span class="s">d Module: </span><span class="si">%(module)</span><span class="s">s Function: </span><span class="si">%(funcName)</span><span class="s">s Time: </span><span class="si">%(asctime)</span><span class="s">s Message: </span><span class="si">%(message)</span><span class="s">s '''</span><span class="p">))</span> <span class="n">app</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">mail_handler</span><span class="p">)</span> <span class="nd">@app.route</span><span class="p">(</span><span class="s">'/error'</span><span class="p">)</span> <span class="k">def</span> <span class="nf">error</span><span class="p">():</span> <span class="k">raise</span> <span class="nb">Exception</span><span class="p">(</span><span class="s">"Beds are burning!"</span><span class="p">)</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span> <span class="c">#app.run(debug=True) #Handler isn't executed if app is run in debug mode</span> <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span> </code></pre> </div>