Permalink
Browse files

Initial commit.

  • Loading branch information...
1 parent 1f48963 commit 1571446fe98af4c1c9e60cecd19ce0d9ab291ffe @sjl sjl committed Oct 3, 2011
Showing with 192 additions and 0 deletions.
  1. +19 −0 LICENSE.markdown
  2. +69 −0 README.markdown
  3. +6 −0 project.clj
  4. +64 −0 src/postmark/core.clj
  5. +34 −0 test/postmark/test/core.clj
View
@@ -0,0 +1,19 @@
+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.
+
View
@@ -0,0 +1,69 @@
+# 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.
View
@@ -0,0 +1,6 @@
+(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"]])
View
@@ -0,0 +1,64 @@
+(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))
+
@@ -0,0 +1,34 @@
+(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"))

0 comments on commit 1571446

Please sign in to comment.