Commits

Steve Losh committed eb0c388

Initial commit.

  • Participants
  • Parent commits 71e3f90
  • Tags v1.0.0

Comments (0)

Files changed (5)

+Copyright (c) 2011 Steve Losh and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# clojure-postmark
+
+`clojure-postmark` lets you talk [Postmark](http://postmarkapp.com/) from
+Clojure.
+
+* Source (Mercurial): <http://bitbucket.org/sjl/clojure-postmark>
+* Source (Git): <http://github.com/sjl/clojure-postmark>
+* Issues: <http://github.com/sjl/clojure-postmark/issues>
+* License: [MIT/X11](http://www.opensource.org/licenses/mit-license.php)
+
+## Installation
+
+Slap this in your `project.clj` `:dependencies`:
+
+    [postmark "1.0.0"]
+
+## Usage
+
+First you need to load the `postmark` function:
+
+    ;; In an (ns)
+    (:use [postmark.core :only (postmark)])
+
+    ;; Outside an (ns)
+    (use '[postmark.core :only (postmark)])
+
+Create a customized `postmark` function:
+
+    (def pm (postmark "YOUR_API_KEY" "from-address@example.com"))
+
+Now just call the function to send an email:
+
+    (pm {:to "fluffy@example.com"
+         :subject "Your Noms"
+         :text "I wants them."})
+
+You can send to multiple addresses by using a seq for `:to`, but remember that
+Postmark's API won't let you send to more than twenty recipients at a time:
+
+    (pm {:to ["fluffy@example.com" "sprinkles@example.com"]
+         :subject "All of Your Noms"
+         :text "I wants them."})
+
+There are a few other keys you can use in the map you pass to the call:
+
+    (pm {:to ["fluffy@example.com" "sprinkles@example.com"]
+         :cc ["haiku@example.com"]
+         :bcc ["admin@example.com"]
+         :subject "All of Your Noms"
+         :text "I wants them."
+         :html "I <b>wants</b> them."
+         :tag "Noms"
+         :reply-to "avedon@example.com"})
+
+## Testing
+
+If you just want to run a test you can use `postmark-test` without an API key
+instead of `postmark`:
+
+    (use '[postmark.core :only (postmark-test)])
+    (def pt (postmark-test "from-address@example.com"))
+
+    (pt {:to ["fluffy@example.com" "sprinkles@example.com"]
+         :subject "Testing"
+         :text "I might want your noms."})
+
+## Todo List
+
+* Automatically generate plain text body if you just pass an html body.
+(defproject postmark "1.0.0"
+  :description "Clojure bindings for http://postmarkapp.com/"
+  :dependencies [[org.clojure/clojure "1.2.1"]
+                 [cheshire "2.0.2"]
+                 [clj-http "0.2.1"]]
+  :dev-dependencies [[lein-marginalia "0.6.1"]])

src/postmark/core.clj

+(ns postmark.core
+  (:require [clj-http.client :as client])
+  (:use [clojure.string :only (join)])
+  (:use [cheshire.core :only (generate-string parse-string)]))
+
+
+;; # Internal Functions
+(defn- maybe-assoc [m k v]
+  (if v
+    (assoc m k v)
+    m))
+
+(defn- parse-mail [mail]
+  (generate-string
+    (loop [m {}
+           ks (keys mail)
+           vs (vals mail)]
+      (if (seq ks)
+        (recur (maybe-assoc m (first ks) (first vs))
+               (rest ks)
+               (rest vs))
+        m))))
+
+(defn- send-to-postmark [api-key mail]
+  (let [resp (client/post "http://api.postmarkapp.com/email"
+                          {:basic-auth ["user" "pass"]
+                           :body (parse-mail mail)
+                           :headers {"X-Postmark-Server-Token" api-key}
+                           :content-type :json
+                           :accept :json})
+        body (parse-string (:body resp))]
+    (assoc resp :body body)))
+
+(defn- get-to-string [to]
+  (when to
+    (if (= java.lang.String (class to))
+      to
+      (join "," to))))
+
+(defn- mail
+  "Send an email with the Postmark API.
+
+  Remember: Postmark only lets you send to at most twenty addresses at once."
+  [api-key from mail]
+  {:pre [(or (= java.lang.String (class (:to mail)))
+             (<= (count (:to mail)) 20))]}
+  (send-to-postmark api-key {"From" from
+                             "To" (get-to-string (:to mail))
+                             "Subject" (:subject mail)
+                             "Cc" (get-to-string (:cc mail))
+                             "Bcc" (get-to-string (:bcc mail))
+                             "Tag" (:tag mail)
+                             "TextBody" (:text mail)
+                             "HtmlBody" (:html mail)
+                             "ReplyTo" (:reply-to mail)}))
+
+
+;; # External API
+(defn postmark [api-key from]
+  (partial mail api-key from))
+
+(defn postmark-test [from]
+  (postmark "POSTMARK_API_TEST" from))
+

test/postmark/test/core.clj

+(ns postmark.test.core
+  (:use [postmark.core])
+  (:use [cheshire.core :only (generate-string parse-string)])
+  (:use [clojure.test]))
+
+(deftest test-maybe-assoc
+  (is (= (@#'postmark.core/maybe-assoc {:foo 1} :bar 2)
+         {:foo 1 :bar 2})
+      "maybe-assoc didn't work with a truthy value")
+
+  (is (= (@#'postmark.core/maybe-assoc {:foo 1} :bar nil)
+         {:foo 1})
+      "maybe-assoc didn't work with a falsy value"))
+
+(deftest test-parse-mail
+  (is (= (@#'postmark.core/parse-mail {"Subject" "foo" "Nothing" nil})
+         (generate-string {"Subject" "foo"}))
+      "parse mail"))
+
+(deftest test-get-to-string
+  (is (= (@#'postmark.core/get-to-string nil)
+         nil)
+      "get-to-string didn't handle nil")
+  (is (= (@#'postmark.core/get-to-string "foo")
+         "foo")
+      "get-to-string didn't pass a string through")
+
+  (is (= (@#'postmark.core/get-to-string ["foo"])
+         "foo")
+      "get-to-string didn't pass a string in a seq through")
+
+  (is (= (@#'postmark.core/get-to-string ["foo" "bar"])
+         "foo,bar")
+      "get-to-string didn't join a seq properly"))