postmark 0.1.1 → 0.2.7
raw patch · 9 files changed
Files
- postmark.cabal +15/−16
- src/Network/Api/Postmark.hs +37/−8
- src/Network/Api/Postmark/Core.hs +9/−0
- src/Network/Api/Postmark/Data.hs +111/−2
- src/Network/Api/Postmark/Error.hs +32/−3
- src/Network/Api/Postmark/Request.hs +4/−1
- src/Network/Api/Postmark/Response.hs +7/−1
- src/Network/Api/Postmark/Settings.hs +50/−5
- src/Network/Api/Postmark/Tutorial.hs +1/−1
postmark.cabal view
@@ -1,5 +1,5 @@ Name: postmark-Version: 0.1.1+Version: 0.2.7 License: BSD3 License-File: LICENSE Author: Mark Hibberd <mark@hibberd.id.au>@@ -11,31 +11,29 @@ Bug-reports: https://github.com/apiengine/postmark/issues Cabal-Version: >= 1.8 Build-Type: Simple+Tested-With: GHC == 7.10.3, GHC == 8.0.2 Description:- postmark+ Library for postmarkapp.com HTTP Api. Source-Repository head Type: git Location: https://github.com/apiengine/postmark.git -Flag small_base- Description: Choose the new, split-up base package.- Flag demo Description: Build the demo executable. Default: False Library Build-Depends:- base >= 3 && < 5- , aeson >= 0.6- , attoparsec >= 0.10- , bytestring >= 0.9- , containers >= 0.4- , http-types >= 0.6- , text >= 0.11- , network-api-support >= 0.1.0- , http-client-tls >= 0.2.1.1+ base >= 3 && < 5+ , aeson >= 0.6 && < 2+ , attoparsec >= 0.10 && < 0.14+ , bytestring >= 0.9 && < 0.11+ , containers >= 0.4 && < 0.7+ , http-types >= 0.6 && < 1+ , text >= 0.11 && < 1.3+ , network-api-support >= 0.3.0 && < 0.4+ , http-client-tls >= 0.2.1.1 && < 0.4 GHC-Options:@@ -54,15 +52,16 @@ Network.Api.Postmark.Settings Network.Api.Postmark.Tutorial + executable postmark-demo if flag(demo) Buildable: True else Buildable: False - ghc-options: -Wall -threaded -O2+ ghc-options: -Wall -threaded main-is: ../demo/demo.hs- hs-source-dirs: dist demo+ hs-source-dirs: demo build-depends: base , postmark , text
src/Network/Api/Postmark.hs view
@@ -7,11 +7,12 @@ -- -- Library for postmarkapp.com HTTP Api. ----- To get start see some examples in the 'Network.Api.Postmark.Tutorial' module at <http://hackage.haskell.org/packages/archive/postmark/0.0.2/doc/html/Network-Api-Postmark-Tutorial.html>.+-- To get start see some examples in the "Network.Api.Postmark.Tutorial" module. -- -- Source and more information can be found at <https://github.com/apiengine/postmark>. -- -- To experiment with a live demo try:+-- -- > $ git clone https://github.com/apiengine/postmark -- > $ cd postmark -- > $ cabal install --only-dependencies && cabal configure -f demo && cabal build@@ -19,11 +20,39 @@ -- -- Issues can be reported at <https://github.com/apiengine/postmark/issues>. ---module Network.Api.Postmark (module X) where+module Network.Api.Postmark ( -import Network.Api.Postmark.Core as X-import Network.Api.Postmark.Data as X hiding (ojson, oljson, omjson, toText)-import Network.Api.Postmark.Error as X-import Network.Api.Postmark.Request as X-import Network.Api.Postmark.Response as X-import Network.Api.Postmark.Settings as X+ -- * Settings+ PostmarkSettings (..), PostmarkApiToken, postmarkHttp, postmarkHttps,+ -- ** Using the test token+ postmarkTestToken, postmarkHttpTest, postmarkHttpsTest,++ -- * Sending email+ email, emails, Email (..), defaultEmail,+ -- ** Using a template+ emailWithTemplate, EmailWithTemplate (..), defaultEmailWithTemplate,+ -- ** Tracking links+ TrackLinks (..),+ -- ** Attachments+ Attachment (..),+ -- ** Response type+ Sent (..),++ -- * Error types+ PostmarkError (..), PostmarkErrorType (..),++ -- * Lower-level API+ -- ** Request+ request, PostmarkRequest (..), PostmarkRequest',+ -- ** Response+ PostmarkResponse (..), PostmarkUnexpectedType (..),+ PostmarkResponse', syntaxErr, formatErr,++) where++import Network.Api.Postmark.Core+import Network.Api.Postmark.Data+import Network.Api.Postmark.Error+import Network.Api.Postmark.Request+import Network.Api.Postmark.Response+import Network.Api.Postmark.Settings
src/Network/Api/Postmark/Core.hs view
@@ -1,8 +1,14 @@ {-# LANGUAGE OverloadedStrings #-} module Network.Api.Postmark.Core (++ -- * API endpoints email, emails,+ emailWithTemplate,++ -- * Run a request request+ ) where import qualified Data.ByteString.Lazy as BL@@ -28,6 +34,9 @@ emails :: [Email] -> PostmarkRequest' [Sent] emails es = PostmarkRequest POST "/email/batch" $ setJson es +-- | Send a single email using a template: https://postmarkapp.com/developer/api/templates-api#email-with-template+emailWithTemplate :: EmailWithTemplate -> PostmarkRequest' Sent+emailWithTemplate ewt = PostmarkRequest POST "/email/withTemplate" $ setJson ewt -- * Run a request
src/Network/Api/Postmark/Data.hs view
@@ -1,8 +1,32 @@ {-# LANGUAGE OverloadedStrings, GADTSyntax #-}-module Network.Api.Postmark.Data where+module Network.Api.Postmark.Data ( -import Control.Applicative+ -- * Request types + -- ** Email+ Email (..),+ defaultEmail,++ -- ** Email with template+ EmailWithTemplate (..),+ defaultEmailWithTemplate,++ -- ** Track links+ TrackLinks (..),++ -- ** Attachment+ Attachment (..),++ -- ** Response type+ Sent (..),++ -- * Internal Json tools+ ojson,+ oljson,+ omjson,+ toText+) where+ import qualified Data.ByteString.Lazy as BL import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy.Encoding as LE@@ -34,15 +58,47 @@ , emailText :: Maybe Text , emailReplyTo :: Text , emailHeaders :: Map Text Text+ , emailTrackOpens :: Maybe Bool+ , emailTrackLinks :: Maybe TrackLinks , emailAttachments :: [Attachment] } +-- | When “link tracking” is enabled, Postmark will record statistics when a+-- user clicks on a link in an email. You can use this feature to determine+-- if a particular recipient has clicked a link that was emailed to them.+--+-- https://postmarkapp.com/developer/user-guide/tracking-links#enabling-link-tracking+data TrackLinks+ = None -- ^ No links will be replaced or tracked.+ | HtmlAndText -- ^ Links will be replaced in both HTML and text bodies.+ | HtmlOnly -- ^ Links will be replaced in only the HTML body. You may+ -- want this option if you do not want encoded tracking+ -- links to appear in the plain text of an email.+ | TextOnly -- ^ Links will be replaced in only the text body.+ deriving (Show)+ data Attachment = Attachment { attachmentName :: Text , attachmentContent :: Text , attachmentContentType :: Text } +data EmailWithTemplate = EmailWithTemplate {+ templateId :: Int+ , templateModel :: Map Text Text+ , inlineCss :: Bool+ , emailFrom' :: Text+ , emailTo' :: [Text]+ , emailCc' :: [Text]+ , emailBcc' :: [Text]+ , emailTag' :: Maybe Text+ , emailReplyTo' :: Text+ , emailHeaders' :: Map Text Text+ , emailTrackOpens' :: Maybe Bool+ , emailTrackLinks' :: Maybe TrackLinks+ , emailAttachments' :: [Attachment]+ }+ defaultEmail :: Email defaultEmail = Email { emailFrom = ""@@ -55,9 +111,27 @@ , emailText = Nothing , emailReplyTo = "" , emailHeaders = M.empty+ , emailTrackOpens = Nothing+ , emailTrackLinks = Nothing , emailAttachments = [] } +defaultEmailWithTemplate :: EmailWithTemplate+defaultEmailWithTemplate = EmailWithTemplate {+ templateId = 0+ , templateModel = M.empty+ , inlineCss = False+ , emailFrom' = ""+ , emailTo' = []+ , emailCc' = []+ , emailBcc' = []+ , emailTag' = Nothing+ , emailReplyTo' = ""+ , emailHeaders' = M.empty+ , emailTrackOpens' = Nothing+ , emailTrackLinks' = Nothing+ , emailAttachments' = []+ } instance ToJSON Email where toJSON v = object ([@@ -72,15 +146,50 @@ , oljson "Cc" (emailCc v) (T.intercalate ",") , oljson "Bcc" (emailBcc v) (T.intercalate ",") , omjson "Headers" (emailHeaders v)+ , ojson "TrackOpens" (emailTrackOpens v)+ , ojson "TrackLinks" (emailTrackLinks v) , oljson "Attachments" (emailAttachments v) id ]) +{- The reason we are being explicit here is because the serialized constructors+ for TrackLinks match the possible values in the Postmark API.+ We don't want to send values wholesale if new constructors come along.+-}+instance ToJSON TrackLinks where+ toJSON v =+ toJSON $ case v of+ None ->+ "None" :: Text+ HtmlAndText ->+ "HtmlAndText"+ HtmlOnly ->+ "HtmlOnly"+ TextOnly ->+ "TextOnly"+ instance ToJSON Attachment where toJSON v = object [ "Name" .= attachmentName v , "Content" .= attachmentContent v , "ContentType" .= attachmentContentType v ]++instance ToJSON EmailWithTemplate where+ toJSON v = object ([+ "TemplateId" .= templateId v+ , "TemplateModel" .= templateModel v+ , "From" .= (emailFrom' v)+ , "To" .= T.intercalate "," (emailTo' v)+ , "ReplyTo" .= emailReplyTo' v+ ] ++ catMaybes [+ ojson "Tag" (emailTag' v)+ , oljson "Cc" (emailCc' v) (T.intercalate ",")+ , oljson "Bcc" (emailBcc' v) (T.intercalate ",")+ , omjson "Headers" (emailHeaders' v)+ , ojson "TrackOpens" (emailTrackOpens' v)+ , ojson "TrackLinks" (emailTrackLinks' v)+ , oljson "Attachments" (emailAttachments' v) id+ ]) -- * Response types
src/Network/Api/Postmark/Error.hs view
@@ -1,7 +1,8 @@ {-# LANGUAGE OverloadedStrings, GADTSyntax #-}-module Network.Api.Postmark.Error where--import Control.Applicative+module Network.Api.Postmark.Error (+ PostmarkError (..),+ PostmarkErrorType (..)+) where import Data.Aeson import Data.Text@@ -27,6 +28,13 @@ | PostmarkBounceQueryException | PostmarkJsonRequired | PostmarkTooManyMessages+ | PostmarkTemplateQueryException+ | PostmarkTemplateNotFound+ | PostmarkTemplateLimitWouldBeExceeded+ | PostmarkTemplateNoDataReceived+ | PostmarkTemplateRequiredFieldMissing+ | PostmarkTemplateFieldTooLarge+ | PostmarkTemplateFieldInvalid | PostmarkUnkownError Int deriving Eq @@ -46,6 +54,13 @@ 408 -> PostmarkBounceQueryException 409 -> PostmarkJsonRequired 410 -> PostmarkTooManyMessages+ 1100 -> PostmarkTemplateQueryException+ 1101 -> PostmarkTemplateNotFound+ 1105 -> PostmarkTemplateLimitWouldBeExceeded+ 1109 -> PostmarkTemplateNoDataReceived+ 1120 -> PostmarkTemplateRequiredFieldMissing+ 1121 -> PostmarkTemplateFieldTooLarge+ 1122 -> PostmarkTemplateFieldInvalid _ -> PostmarkUnkownError code) (o .: "ErrorCode")) <*> (o .: "Message") parseJSON _ = fail "Invalid Postmark Error Response"@@ -75,5 +90,19 @@ "Your HTTP request does not have the Accept and Content-Type headers set to application/json." show PostmarkTooManyMessages = "Your batched request contains more than 500 messages."+ show PostmarkTemplateQueryException =+ "The value of a GET parameter for the request is not valid."+ show PostmarkTemplateNotFound =+ "TemplateId not found. The TemplateId references a Template that does not exist, or is not associated with the Server specified for this request."+ show PostmarkTemplateLimitWouldBeExceeded =+ "Template limit would be exceeded. A Server may have up to 300 active templates, processing this request would exceed this limit."+ show PostmarkTemplateNoDataReceived =+ "No Template data received. You didn’t provide JSON body parameters in your request. Refer to the Template API reference for more details on required parameters."+ show PostmarkTemplateRequiredFieldMissing =+ "A required Template field is missing. A required field is missing from the body of the POST request."+ show PostmarkTemplateFieldTooLarge =+ "Template field is too large. One of the values of the request's body exceeds our size restrictions for that field."+ show PostmarkTemplateFieldInvalid =+ "A Templated field has been submitted that is invalid. One of the fields of the request body is invalid." show (PostmarkUnkownError code) = "An unexpected error code [" ++ show code ++ "] was retured from postmark."
src/Network/Api/Postmark/Request.hs view
@@ -1,5 +1,8 @@ {-# LANGUAGE GADTs, GADTSyntax #-}-module Network.Api.Postmark.Request where+module Network.Api.Postmark.Request (+ PostmarkRequest (..),+ PostmarkRequest'+) where import Network.Api.Postmark.Error
src/Network/Api/Postmark/Response.hs view
@@ -1,4 +1,10 @@-module Network.Api.Postmark.Response where+module Network.Api.Postmark.Response (+ PostmarkResponse (..),+ PostmarkUnexpectedType (..),+ PostmarkResponse',+ syntaxErr,+ formatErr+) where import qualified Data.ByteString.Lazy as BL import Data.Text
src/Network/Api/Postmark/Settings.hs view
@@ -1,25 +1,70 @@ {-# LANGUAGE OverloadedStrings #-}-module Network.Api.Postmark.Settings where+module Network.Api.Postmark.Settings ( + -- * Settings types+ PostmarkSettings (..),+ PostmarkApiToken,++ -- * Settings construction+ postmarkHttp,+ postmarkHttps,++ -- * Using the test token+ postmarkTestToken,+ postmarkHttpTest,+ postmarkHttpsTest++) where+ import Data.Text +-- | The Postmark “server token” which is sent via the+-- @X-Postmark-Server-Token@ HTTP header. You can find your server+-- token under the “Credentials” tab on the Postmark website.+--+-- If you do not yet have a Postmark account, or if you want to send+-- test emails that don't actually get delivered, you may use+-- 'postmarkTestToken'.+--+-- https://postmarkapp.com/developer/api/overview#authentication+type PostmarkApiToken = Text++-- | To construct 'PostmarkSettings', use 'postmarkHttps' or+-- 'postmarkHttp'.+--+-- Or to use the test API instead, use 'postmarkHttpsTest' or+-- 'postmarkHttpTest'. data PostmarkSettings = PostmarkSettings { apiUrl :: Text- , apiToken :: Text+ , apiToken :: PostmarkApiToken } deriving (Eq, Show) -postmarkTestToken :: Text+-- | An API token that you can use when you want to send test emails that+-- don't actually get delivered to the recipient.+--+-- https://postmarkapp.com/developer/api/overview#authentication+postmarkTestToken :: PostmarkApiToken postmarkTestToken = "POSTMARK_API_TEST" +-- | Postmark settings using the HTTP protocol and the test API token+-- ('postmarkTestToken').+--+-- HTTPS is recommended instead ('postmarkHttpsTest'). postmarkHttpTest :: PostmarkSettings postmarkHttpTest = postmarkHttp postmarkTestToken +-- | Postmark settings using the HTTPS protocol and the test API token+-- ('postmarkTestToken'). postmarkHttpsTest :: PostmarkSettings postmarkHttpsTest = postmarkHttps postmarkTestToken -postmarkHttp :: Text -> PostmarkSettings+-- | Constructs Postmark settings using the HTTP protocol and your API token.+--+-- HTTPS is recommended instead ('postmarkHttps').+postmarkHttp :: PostmarkApiToken -> PostmarkSettings postmarkHttp = PostmarkSettings "http://api.postmarkapp.com" -postmarkHttps :: Text -> PostmarkSettings+-- | Constructs Postmark settings using the HTTPS protocol and your API token.+postmarkHttps :: PostmarkApiToken -> PostmarkSettings postmarkHttps = PostmarkSettings "https://api.postmarkapp.com"
src/Network/Api/Postmark/Tutorial.hs view
@@ -50,7 +50,7 @@ > import Network.Api.Postmark >-> demo = request postmarkHttpTrest $ emails [+> demo = request postmarkHttpTest $ emails [ > defaultEmail { > emailFrom = "demo-from@postmark.hs" > , emailTo = ["demo-to@postmark.hs"]