ARCHIVED: We no longer use this project, so we are not actively maintaining it. Please see here for possible alternatives.
Haskell interface to the SendGrid API.
tl;dr:
- install with Stack
- use
mkSingleRecipemail to construct an email - use Lenses to update properties of the email (such as templates, categories, or unsubscribe groups.
- run the reader monad with the
ApiKey
Add the following to your stack.yaml under packages:
packages:
- location:
git: git://github.com/frontrowed/sendgrid
commit: <COMMIT>The primary data type is SendEmail, which represents the components
of an email message that may be sent via SendGrid. Properties of a
SendEmail include the standard email components such as sender, CC
and BCC recipients, attachements, and so forth. Additionally,
SendGrid-specific attributes include templates, categories, and
unsubscribe groups.
Consider the following definition of a simple email from
sender@source.com to receiver@person.com. It has the subject
"Coming via sendgrid" and contents "Text body". The type indicates
that the message categories are Text, one recipient (Vector 1),
and no CC or BCC recipients (Vector 0).
email1 :: SendEmail Text (Vector 1) (Vector 0) (Vector 0)
email1 =
let [sender, recipient] = map (uncurry unsafeEmailAddress) [
("sender", "source.com"),
("receiver", "person.com")
]
in
mkSingleRecipEmail
recipient
"Coming via sendgrid"
(That "Text body")
senderSendEMail types can additionaly be modified using Lenses to modify
the components. Use the SendEmail lenses and lens operator set the
desired attributes. For instance, to set the categories and unsubscribe group:
email2 :: SendMail Text (Vector 1) (Vector 0) (Vector 0)
email2 = email1
& categories .~ ["email", "test", "foo", "bar"]
& templateId .~ Just "ff469da0-4a45-4263-2414-5ac770565e4d"We use type indices to typecheck the number of CC and BCC recipients. To set and add to each of these, you need to construct a typechecked vector
To add CC and BCC recipients you can use the ccsAll and ``bccsAll`
lens, which accepts a tuple of type-indexed vectors where the second
is wrapped with Maybe.
email3 =
let cc1 = unsafeEmailAddress "cc1" "example.com"
cc2 = unsafeEmailAddress "cc2" "example.com"
n1 = "CC 1 name"
n2 = "CC 2 name"
in email2
& ccsAll .~ (cc2 #: cc1 #: empty, Just $ n2 #: n1 #: empty)This can be rather unwieldy, so the ccsWipe and bccsWipe lenses
are provided. As the names hint at, these "wipe" the names list so
make sure to use the paired ccNames and bccNames lenses to set
the names.
email4 :: SendMail Text (Vector 1) (Vector 2) (Vector 0)
email4 =
let cc1 = unsafeEmailAddress "cc1" "example.com"
cc2 = unsafeEmailAddress "cc2" "example.com"
n1 = "CC 1"
n2 = "CC 2"
in email2
& ccsWipe .~ (cc2 #: cc1 #: empty)
& ccNames .~ (Just $ n2 #: n1 #: empty)Finally, to actually send an email, you'll need to use an ApiKey and
construct a Wreq session. One approach is to set this as an
environmental variable and then load it using
System.Environment.lookupEnv
main = do
key <- fmap (Tagged . T.pack) <$> lookupEnv "API_KEY"
maybe
(fail "Could not lookup API_KEY in environment")
sendMyEmail
keyThe sendEmail function operates in the Reader Monad with
configuration given as 2-tuple type (Tagged ApiKey Text, Session).
sendMyEmail :: Tagged ApiKey Text -> IO ()
sendMyEmail apikey = do
result <- withSession $ \session ->
runReaderT (sendEmail email4) (apikey, session)
print result