diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/resources/postmark/devel.cfg b/resources/postmark/devel.cfg
new file mode 100644
--- /dev/null
+++ b/resources/postmark/devel.cfg
@@ -0,0 +1,1 @@
+secret_key = ""
diff --git a/snaplet-postmark.cabal b/snaplet-postmark.cabal
new file mode 100644
--- /dev/null
+++ b/snaplet-postmark.cabal
@@ -0,0 +1,38 @@
+name:           snaplet-postmark
+version:        0.1.0
+synopsis:       Postmark snaplet for the Snap Framework
+description:    This snaplet contains support for using the Postmark
+                email system with a Snap Framework application.
+license:        BSD3
+author:         Luke Hoersten
+maintainer:     luke@hoersten.org
+build-type:     Simple
+cabal-version:  >= 1.6
+homepage:       https://github.com/LukeHoersten/snaplet-postmark
+category:       Web, Snap
+
+data-files:
+  resources/postmark/devel.cfg
+
+source-repository head
+  type:     git
+  location: https://github.com/LukeHoersten/snaplet-postmark
+
+Library
+  hs-source-dirs: src
+
+  exposed-modules:
+    Snap.Snaplet.Postmark
+
+  build-depends:
+    base         >= 4.4     && < 5,
+    snap         >= 0.11    && < 0.14,
+    text         >= 0.11    && < 0.12,
+    configurator >= 0.2     && < 0.3,
+    transformers >= 0.3     && < 0.4,
+    mtl          >= 2       && < 3,
+    postmark     >= 0.0.2   && < 0.2
+
+
+  ghc-options: -Wall -fwarn-tabs -funbox-strict-fields
+               -fno-warn-orphans -fno-warn-unused-do-bind
diff --git a/src/Snap/Snaplet/Postmark.hs b/src/Snap/Snaplet/Postmark.hs
new file mode 100644
--- /dev/null
+++ b/src/Snap/Snaplet/Postmark.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Snap.Snaplet.Postmark where
+
+import           Control.Applicative        ((<$>))
+import           Control.Monad              (when)
+import           Control.Monad.State        (get)
+import           Control.Monad.Trans        (MonadIO, liftIO)
+import           Control.Monad.Trans.Writer (WriterT (..), tell)
+import qualified Data.Configurator          as C
+import           Data.List                  (intercalate)
+import           Data.Maybe                 (fromMaybe, isNothing)
+import qualified Data.Text                  as T
+import           Network.Api.Postmark       (Email (..), PostmarkError,
+                                             PostmarkResponse, PostmarkSettings,
+                                             Sent, email, emails, postmarkHttps,
+                                             request)
+import           Snap.Snaplet               (Handler, SnapletInit,
+                                             getSnapletUserConfig, makeSnaplet)
+
+
+newtype Postmark = Postmark { unPostmark :: PostmarkSettings } deriving Show
+
+
+class (MonadIO m, Functor m) => HasPostmark m where
+    getPostmark :: m Postmark
+
+
+instance HasPostmark (Handler b Postmark) where
+    getPostmark = get
+
+
+logErr :: MonadIO m => t -> IO (Maybe a) -> WriterT [t] m (Maybe a)
+logErr err m = do
+  res <- liftIO m
+  when (isNothing res) (tell [err])
+  return res
+
+
+initPostmark :: SnapletInit b Postmark
+initPostmark = makeSnaplet "postmark" "Postmark email client" Nothing $ do
+  config <- getSnapletUserConfig
+  (mscfg, errs) <- runWriterT $ do
+    secretKey <- logErr "Must specify Strip secret key" $ C.lookup config "secret_key"
+    return $ Postmark <$> (postmarkHttps <$> (T.pack <$> secretKey))
+  return $ fromMaybe (error $ intercalate "\n" errs) mscfg
+
+
+withPS :: HasPostmark m => (PostmarkSettings -> m a) -> m a
+withPS f = unPostmark <$> getPostmark >>= f
+
+
+sendEmail :: HasPostmark m => Email -> m (PostmarkResponse PostmarkError Sent)
+sendEmail msg = withPS $ liftIO . flip request (email msg)
+
+
+sendEmails :: HasPostmark m => [Email] -> m (PostmarkResponse PostmarkError [Sent])
+sendEmails msgs = withPS $ liftIO . flip request (emails msgs)
