Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
(ns paddleguru.util.mandrill
"Methods for interacting with the Mandrill API."
(:require [cheshire.core :as json]
[clojure.core.async :as a]
[org.httpkit.client :as http]
[paddleguru.config :as conf]
[paddleguru.schema :refer [Channel]]
[paddleguru.util :refer [collectify]]
[schema.core :as s]
[taoensso.timbre :as log])
(:import (clojure.lang ISeq)))
;; ## Schemas
(defprotocol Mailable
(mail [this]
"Coerces the body into HTML suitable for sending via email."))
(extend-protocol Mailable
(mail [_] nil)
(mail [s] s)
(mail [coll] (apply str coll)))
(def Key (s/named s/Str "API key for Mandrill."))
(def Address
"TODO: Have this actually use a schema that detects if we're dealing
with an email address or not."
(s/named s/Str "email address."))
(def Email
{:to-email (s/either Address [Address])
(s/optional-key :from-email) Address
:subject s/Str
:body (s/either s/Str [s/Str])})
;; ## Private
(s/defn conf-key :- Key
(:key (conf/get-config :mandrill)))
(def mandrill-url
(s/defn method-url
"URL for calling a method"
[method :- String]
(str mandrill-url method ".json"))
(defn prepare-params
[key params opts]
(let [base-params {:headers {"Content-Type" "application/json; charset=utf-8"}
:body (json/generate-string (assoc params :key key))}]
(merge base-params opts)))
;; ## Public Methods
(s/defn api-call :- Channel
"Call an API method on Mandrill. Returns a core.async channel
The available options are:
Example calls:
(api-call \"users/ping\" {:id \"a1a1a1a1a1\"})
(api-call \"users/ping\" {:id \"a1a1a1a1a1\"} {:socket-timeout 1000})
(api-call \"users/ping\" {:id \"a1a1a1a1a1\"} {:socket-timeout 1000})"
[key :- Key method :- s/Str & [params opts]]
(let [c (a/chan)
url (method-url method)
params (prepare-params key params opts)]
(http/post url params
(fn [ret]
(a/put! c (json/parse-string (:body ret)))))
(s/defn send-message :- Channel
"Send a message. Pass in a message map.
[key :- Key {:keys [to-email subject body from-email]
:or {from-email ""}} :- Email]
(when-let [to-email (not-empty (collectify to-email))]
(let [message {:html (mail body)
:from_email from-email
:from_name "PaddleGuru"
:to (map (fn [e] {:email e}) to-email)
:track_opens true
:track_clicks true
:auto_text true
:inline_css true
:subject subject}]
(api-call key "messages/send" {:message message}))))
(s/defn send-template :- Channel
"Send a message based on a template . Pass in a template name,
message map and an optional template-content array.
([key :- Key template message]
(send-template template message []))
([key :- Key template message template-content]
(api-call "messages/send-template" {:template_name template
:message message
:template_content template-content})))
(s/defn user-info :- Channel
"Get information about your Mandrill account.
[key :- Key]
(api-call key "users/info"))
(s/defn ping :- Channel
"Validate an API key and respond to a ping.
[key :- Key]
(api-call key "users/ping"))
(s/defn senders :- Channel
"Return the senders that have tried to use this account, both
verified and unverified.
[key :- Key]
(api-call key "users/senders"))
(s/defn send-email :- Channel
"Accepts a recipient email (potentially many), a subject line and a
body (in text form) and sends the message from"
[email :- Email]
(let [key (:key (conf/get-config :mandrill))]
(log/info "send-email" {:email (dissoc email :body)})
(send-message key email)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment