module Network.Mail.Mailtrap
(
Token (..)
, Exception (..)
, AccountID (..)
, Account (..)
, getAllAccounts
, Disposition (..)
, setDisposition
, Attachment (..)
, attachmentFromFile
, Template (..)
, template
, setTemplateVariable
, InboxID (..)
, Inbox (..)
, getInboxes
, InboxMessageID (..)
, InboxMessage (..)
, getInboxMessages
, downloadMessageRaw
, downloadMessageEML
, downloadMessageText
, downloadMessageHTML
, EmailAddress
, parseEmailAddress
, NamedEmailAddress (..)
, MessageID (..)
, Message (..)
, EmailBody (..)
, Email (..)
, sendEmail
, sendTestEmail
) where
import Control.Exception qualified as Base
import GHC.TypeLits (Symbol, KnownSymbol, symbolVal)
import Data.Proxy
import Data.String (fromString)
import Data.Text (Text)
import Data.Text qualified as Text
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import Text.Email.Validate (EmailAddress)
import Text.Email.Validate qualified as Email
import Data.ByteString (ByteString)
import Data.ByteString qualified as ByteString
import Network.Mime (MimeType, defaultMimeLookup)
import Data.Aeson (ToJSON, (.=), FromJSON, (.:))
import Data.Aeson qualified as JSON
#if MIN_VERSION_aeson(2,0,0)
import Data.Aeson.KeyMap qualified as KeyMap
import Data.Aeson.Key qualified as Key
#else
import Data.HashMap.Strict qualified as HashMap
#endif
import Data.ByteString.Base64 (encodeBase64)
import Text.Blaze.Html (Html)
import Text.Blaze.Html.Renderer.Text (renderHtml)
import Data.UUID.Types (UUID)
import Network.HTTP.Simple qualified as HTTP
import System.FilePath (takeFileName)
import Data.Time.Clock (UTCTime)
newtype Token = Token Text deriving (Token -> Token -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Token -> Token -> Bool
$c/= :: Token -> Token -> Bool
== :: Token -> Token -> Bool
$c== :: Token -> Token -> Bool
Eq, Int -> Token -> ShowS
[Token] -> ShowS
Token -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Token] -> ShowS
$cshowList :: [Token] -> ShowS
show :: Token -> String
$cshow :: Token -> String
showsPrec :: Int -> Token -> ShowS
$cshowsPrec :: Int -> Token -> ShowS
Show)
instance FromJSON Token where
parseJSON :: Value -> Parser Token
parseJSON = forall a. String -> (Text -> Parser a) -> Value -> Parser a
JSON.withText String
"Mailtrap Token" (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Token
Token)
instance ToJSON Token where
toJSON :: Token -> Value
toJSON (Token Text
token) = forall a. ToJSON a => a -> Value
JSON.toJSON Text
token
data Exception =
MultipleErrors Int [Text]
| SingleError Int Text
| ParsingError ByteString String
deriving Int -> Exception -> ShowS
[Exception] -> ShowS
Exception -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Exception] -> ShowS
$cshowList :: [Exception] -> ShowS
show :: Exception -> String
$cshow :: Exception -> String
showsPrec :: Int -> Exception -> ShowS
$cshowsPrec :: Int -> Exception -> ShowS
Show
instance Base.Exception Exception
singleError :: Int -> JSONResp "error" Text -> Exception
singleError :: Int -> JSONResp "error" Text -> Exception
singleError Int
code (JSONResp Text
err) = Int -> Text -> Exception
SingleError Int
code Text
err
multipleErrors :: Int -> JSONResp "errors" [Text] -> Exception
multipleErrors :: Int -> JSONResp "errors" [Text] -> Exception
multipleErrors Int
code (JSONResp [Text]
errs) = Int -> [Text] -> Exception
MultipleErrors Int
code [Text]
errs
data JSONResp (k :: Symbol) a = JSONResp { forall (k :: Symbol) a. JSONResp k a -> a
fromJSONResp :: a }
instance (KnownSymbol k, FromJSON a) => FromJSON (JSONResp k a) where
parseJSON :: Value -> Parser (JSONResp k a)
parseJSON =
let k :: Key
k = forall a. IsString a => String -> a
fromString forall a b. (a -> b) -> a -> b
$ forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal forall a b. (a -> b) -> a -> b
$ forall {k} (t :: k). Proxy t
Proxy @k
in forall a. String -> (Object -> Parser a) -> Value -> Parser a
JSON.withObject String
"JSONResp" forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (k :: Symbol) a. a -> JSONResp k a
JSONResp forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. FromJSON a => Object -> Key -> Parser a
.: Key
k)
newtype AsText a = AsText { forall a. AsText a -> a
asText :: a }
instance FromJSON a => FromJSON (AsText a) where
parseJSON :: Value -> Parser (AsText a)
parseJSON = forall a. String -> (Text -> Parser a) -> Value -> Parser a
JSON.withText String
"AsText" forall a b. (a -> b) -> a -> b
$
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall (m :: * -> *) a. MonadFail m => String -> m a
fail (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> AsText a
AsText) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromJSON a => ByteString -> Either String a
JSON.eitherDecodeStrict forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8
genericQuery
:: (FromJSON err, ToJSON a, FromJSON b)
=> ByteString
-> ByteString
-> ByteString
-> Token
-> (Int -> err -> Exception)
-> Maybe a
-> IO b
genericQuery :: forall err a b.
(FromJSON err, ToJSON a, FromJSON b) =>
ByteString
-> ByteString
-> ByteString
-> Token
-> (Int -> err -> Exception)
-> Maybe a
-> IO b
genericQuery ByteString
method ByteString
url ByteString
path (Token Text
token) Int -> err -> Exception
ferr Maybe a
mbody = do
let req :: Request
req = ByteString -> Request -> Request
HTTP.setRequestMethod ByteString
method
forall a b. (a -> b) -> a -> b
$ ByteString -> Request -> Request
HTTP.setRequestHost ByteString
url
forall a b. (a -> b) -> a -> b
$ Int -> Request -> Request
HTTP.setRequestPort Int
443
forall a b. (a -> b) -> a -> b
$ ByteString -> Request -> Request
HTTP.setRequestPath ByteString
path
forall a b. (a -> b) -> a -> b
$ Bool -> Request -> Request
HTTP.setRequestSecure Bool
True
forall a b. (a -> b) -> a -> b
$ forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall a. a -> a
id forall a. ToJSON a => a -> Request -> Request
HTTP.setRequestBodyJSON Maybe a
mbody
forall a b. (a -> b) -> a -> b
$ HeaderName -> ByteString -> Request -> Request
HTTP.addRequestHeader HeaderName
"Api-Token" (Text -> ByteString
encodeUtf8 Text
token)
forall a b. (a -> b) -> a -> b
$ Request
HTTP.defaultRequest
Response ByteString
resp <- forall (m :: * -> *).
MonadIO m =>
Request -> m (Response ByteString)
HTTP.httpBS Request
req
let code :: Int
code = forall a. Response a -> Int
HTTP.getResponseStatusCode Response ByteString
resp
body :: ByteString
body = forall a. Response a -> a
HTTP.getResponseBody Response ByteString
resp
case Int
code of
Int
200 ->
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall e a. Exception e => e -> IO a
Base.throwIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String -> Exception
ParsingError ByteString
body) forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$
forall a. FromJSON a => ByteString -> Either String a
JSON.eitherDecodeStrict ByteString
body
Int
_ ->
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall e a. Exception e => e -> IO a
Base.throwIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String -> Exception
ParsingError ByteString
body) (forall e a. Exception e => e -> IO a
Base.throwIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> err -> Exception
ferr Int
code) forall a b. (a -> b) -> a -> b
$
forall a. FromJSON a => ByteString -> Either String a
JSON.eitherDecodeStrict ByteString
body
noBody :: Maybe ()
noBody :: Maybe ()
noBody = forall a. Maybe a
Nothing
genericDownload
:: ByteString
-> ByteString
-> Token
-> IO ByteString
genericDownload :: ByteString -> ByteString -> Token -> IO ByteString
genericDownload ByteString
url ByteString
path (Token Text
token) = do
let req :: Request
req = ByteString -> Request -> Request
HTTP.setRequestMethod ByteString
"GET"
forall a b. (a -> b) -> a -> b
$ ByteString -> Request -> Request
HTTP.setRequestHost ByteString
url
forall a b. (a -> b) -> a -> b
$ Int -> Request -> Request
HTTP.setRequestPort Int
443
forall a b. (a -> b) -> a -> b
$ ByteString -> Request -> Request
HTTP.setRequestPath ByteString
path
forall a b. (a -> b) -> a -> b
$ Bool -> Request -> Request
HTTP.setRequestSecure Bool
True
forall a b. (a -> b) -> a -> b
$ HeaderName -> ByteString -> Request -> Request
HTTP.addRequestHeader HeaderName
"Api-Token" (Text -> ByteString
encodeUtf8 Text
token)
forall a b. (a -> b) -> a -> b
$ Request
HTTP.defaultRequest
Response ByteString
resp <- forall (m :: * -> *).
MonadIO m =>
Request -> m (Response ByteString)
HTTP.httpBS Request
req
let code :: Int
code = forall a. Response a -> Int
HTTP.getResponseStatusCode Response ByteString
resp
body :: ByteString
body = forall a. Response a -> a
HTTP.getResponseBody Response ByteString
resp
case Int
code of
Int
200 -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ByteString
body
Int
404 -> forall e a. Exception e => e -> IO a
Base.throwIO forall a b. (a -> b) -> a -> b
$ Int -> Text -> Exception
SingleError Int
404 Text
"File not found."
Int
_ ->
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall e a. Exception e => e -> IO a
Base.throwIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String -> Exception
ParsingError ByteString
body) (forall e a. Exception e => e -> IO a
Base.throwIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> JSONResp "error" Text -> Exception
singleError Int
code) forall a b. (a -> b) -> a -> b
$
forall a. FromJSON a => ByteString -> Either String a
JSON.eitherDecodeStrict ByteString
body
newtype AccountID = AccountID Int deriving (AccountID -> AccountID -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AccountID -> AccountID -> Bool
$c/= :: AccountID -> AccountID -> Bool
== :: AccountID -> AccountID -> Bool
$c== :: AccountID -> AccountID -> Bool
Eq, Int -> AccountID -> ShowS
[AccountID] -> ShowS
AccountID -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AccountID] -> ShowS
$cshowList :: [AccountID] -> ShowS
show :: AccountID -> String
$cshow :: AccountID -> String
showsPrec :: Int -> AccountID -> ShowS
$cshowsPrec :: Int -> AccountID -> ShowS
Show, Value -> Parser [AccountID]
Value -> Parser AccountID
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [AccountID]
$cparseJSONList :: Value -> Parser [AccountID]
parseJSON :: Value -> Parser AccountID
$cparseJSON :: Value -> Parser AccountID
FromJSON)
data Account = Account
{ Account -> AccountID
account_id :: AccountID
, Account -> Text
account_name :: Text
} deriving Int -> Account -> ShowS
[Account] -> ShowS
Account -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Account] -> ShowS
$cshowList :: [Account] -> ShowS
show :: Account -> String
$cshow :: Account -> String
showsPrec :: Int -> Account -> ShowS
$cshowsPrec :: Int -> Account -> ShowS
Show
instance FromJSON Account where
parseJSON :: Value -> Parser Account
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
JSON.withObject String
"Account" forall a b. (a -> b) -> a -> b
$ \Object
o ->
AccountID -> Text -> Account
Account forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"id" forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"name"
getAllAccounts :: Token -> IO [Account]
getAllAccounts :: Token -> IO [Account]
getAllAccounts Token
token = forall err a b.
(FromJSON err, ToJSON a, FromJSON b) =>
ByteString
-> ByteString
-> ByteString
-> Token
-> (Int -> err -> Exception)
-> Maybe a
-> IO b
genericQuery ByteString
"GET" ByteString
"mailtrap.io" ByteString
"/api/accounts" Token
token Int -> JSONResp "error" Text -> Exception
singleError Maybe ()
noBody
newtype EmailAddressJSON = EmailAddressJSON { EmailAddressJSON -> EmailAddress
fromEmailAddressJSON :: EmailAddress }
instance ToJSON EmailAddressJSON where
toJSON :: EmailAddressJSON -> Value
toJSON = Text -> Value
JSON.String forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
decodeUtf8 forall b c a. (b -> c) -> (a -> b) -> a -> c
. EmailAddress -> ByteString
Email.toByteString forall b c a. (b -> c) -> (a -> b) -> a -> c
. EmailAddressJSON -> EmailAddress
fromEmailAddressJSON
instance FromJSON EmailAddressJSON where
parseJSON :: Value -> Parser EmailAddressJSON
parseJSON = forall a. String -> (Text -> Parser a) -> Value -> Parser a
JSON.withText String
"EmailAddressJSON" forall a b. (a -> b) -> a -> b
$ \Text
t ->
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall (m :: * -> *) a. MonadFail m => String -> m a
fail (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall b c a. (b -> c) -> (a -> b) -> a -> c
. EmailAddress -> EmailAddressJSON
EmailAddressJSON) forall a b. (a -> b) -> a -> b
$ ByteString -> Either String EmailAddress
Email.validate forall a b. (a -> b) -> a -> b
$ Text -> ByteString
encodeUtf8 Text
t
data NamedEmailAddress = NamedEmailAddress
{ NamedEmailAddress -> EmailAddress
emailAddress :: EmailAddress
, NamedEmailAddress -> Text
emailAddressName :: Text
} deriving Int -> NamedEmailAddress -> ShowS
[NamedEmailAddress] -> ShowS
NamedEmailAddress -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [NamedEmailAddress] -> ShowS
$cshowList :: [NamedEmailAddress] -> ShowS
show :: NamedEmailAddress -> String
$cshow :: NamedEmailAddress -> String
showsPrec :: Int -> NamedEmailAddress -> ShowS
$cshowsPrec :: Int -> NamedEmailAddress -> ShowS
Show
instance ToJSON NamedEmailAddress where
toJSON :: NamedEmailAddress -> Value
toJSON NamedEmailAddress
addr = [Pair] -> Value
JSON.object
[ Key
"email" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= EmailAddress -> EmailAddressJSON
EmailAddressJSON (NamedEmailAddress -> EmailAddress
emailAddress NamedEmailAddress
addr)
, Key
"name" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= NamedEmailAddress -> Text
emailAddressName NamedEmailAddress
addr
]
parseEmailAddress :: ByteString -> Either String EmailAddress
parseEmailAddress :: ByteString -> Either String EmailAddress
parseEmailAddress = ByteString -> Either String EmailAddress
Email.validate
data Disposition =
Inline Text
| Attached
deriving Int -> Disposition -> ShowS
[Disposition] -> ShowS
Disposition -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Disposition] -> ShowS
$cshowList :: [Disposition] -> ShowS
show :: Disposition -> String
$cshow :: Disposition -> String
showsPrec :: Int -> Disposition -> ShowS
$cshowsPrec :: Int -> Disposition -> ShowS
Show
data Attachment = Attachment
{
Attachment -> Text
attachment_name :: Text
, Attachment -> ByteString
attachment_type :: MimeType
, Attachment -> ByteString
attachment_content :: ByteString
, Attachment -> Disposition
attachment_disposition :: Disposition
} deriving Int -> Attachment -> ShowS
[Attachment] -> ShowS
Attachment -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Attachment] -> ShowS
$cshowList :: [Attachment] -> ShowS
show :: Attachment -> String
$cshow :: Attachment -> String
showsPrec :: Int -> Attachment -> ShowS
$cshowsPrec :: Int -> Attachment -> ShowS
Show
attachmentFromFile :: FilePath -> IO Attachment
attachmentFromFile :: String -> IO Attachment
attachmentFromFile String
fp = do
let fptext :: Text
fptext :: Text
fptext = String -> Text
Text.pack forall a b. (a -> b) -> a -> b
$ ShowS
takeFileName String
fp
ByteString
bytes <- String -> IO ByteString
ByteString.readFile String
fp
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Attachment
{ attachment_name :: Text
attachment_name = Text
fptext
, attachment_type :: ByteString
attachment_type = Text -> ByteString
defaultMimeLookup Text
fptext
, attachment_content :: ByteString
attachment_content = ByteString
bytes
, attachment_disposition :: Disposition
attachment_disposition = Disposition
Attached
}
setDisposition :: Disposition -> Attachment -> Attachment
setDisposition :: Disposition -> Attachment -> Attachment
setDisposition Disposition
d Attachment
a = Attachment
a { attachment_disposition :: Disposition
attachment_disposition = Disposition
d }
instance ToJSON Attachment where
toJSON :: Attachment -> Value
toJSON Attachment
att = [Pair] -> Value
JSON.object forall a b. (a -> b) -> a -> b
$
[ Key
"filename" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Attachment -> Text
attachment_name Attachment
att
, Key
"type" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= ByteString -> Text
decodeUtf8 (Attachment -> ByteString
attachment_type Attachment
att)
, Key
"content" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= ByteString -> Text
encodeBase64 (Attachment -> ByteString
attachment_content Attachment
att)
, Key
"disposition" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.=
(case Attachment -> Disposition
attachment_disposition Attachment
att of
Inline Text
_ -> Text
"inline" :: Text
Disposition
Attached -> Text
"attachment"
)
] forall a. [a] -> [a] -> [a]
++ (case Attachment -> Disposition
attachment_disposition Attachment
att of
Inline Text
i -> [ Key
"content_id" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Text
i ]
Disposition
Attached -> []
)
data EmailBody =
PlainTextBody Text
| HTMLOnlyBody Html
| HTMLBody Html Text
data Message = Message
{ Message -> Text
message_subject :: Text
, Message -> EmailBody
message_body :: EmailBody
, Message -> Text
message_category :: Text
}
data Template = Template
{
Template -> UUID
template_id :: UUID
, Template -> Object
template_variables :: JSON.Object
} deriving Int -> Template -> ShowS
[Template] -> ShowS
Template -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Template] -> ShowS
$cshowList :: [Template] -> ShowS
show :: Template -> String
$cshow :: Template -> String
showsPrec :: Int -> Template -> ShowS
$cshowsPrec :: Int -> Template -> ShowS
Show
template :: UUID -> Template
#if MIN_VERSION_aeson(2,0,0)
template :: UUID -> Template
template UUID
i = UUID -> Object -> Template
Template UUID
i forall v. KeyMap v
KeyMap.empty
#else
template i = Template i HashMap.empty
#endif
setTemplateVariable :: ToJSON a => Text -> a -> Template -> Template
setTemplateVariable :: forall a. ToJSON a => Text -> a -> Template -> Template
setTemplateVariable Text
k a
x Template
t =
#if MIN_VERSION_aeson(2,0,0)
Template
t { template_variables :: Object
template_variables = forall v. Key -> v -> KeyMap v -> KeyMap v
KeyMap.insert (Text -> Key
Key.fromText Text
k) (forall a. ToJSON a => a -> Value
JSON.toJSON a
x) forall a b. (a -> b) -> a -> b
$ Template -> Object
template_variables Template
t }
#else
t { template_variables = HashMap.insert k (JSON.toJSON x) $ template_variables t }
#endif
data Email = Email
{
Email -> NamedEmailAddress
email_from :: NamedEmailAddress
, Email -> [NamedEmailAddress]
email_to :: [NamedEmailAddress]
, Email -> [NamedEmailAddress]
email_cc :: [NamedEmailAddress]
, Email -> [NamedEmailAddress]
email_bcc :: [NamedEmailAddress]
, Email -> [Attachment]
email_attachments :: [Attachment]
, Email -> Object
email_custom :: JSON.Object
, Email -> Either Template Message
email_message :: Either Template Message
}
instance ToJSON Email where
toJSON :: Email -> Value
toJSON Email
email = [Pair] -> Value
JSON.object forall a b. (a -> b) -> a -> b
$
[ Key
"from" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Email -> NamedEmailAddress
email_from Email
email
, Key
"to" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Email -> [NamedEmailAddress]
email_to Email
email
, Key
"cc" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Email -> [NamedEmailAddress]
email_cc Email
email
, Key
"bcc" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Email -> [NamedEmailAddress]
email_bcc Email
email
, Key
"attachments" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Email -> [Attachment]
email_attachments Email
email
, Key
"custom_variables" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Email -> Object
email_custom Email
email
] forall a. [a] -> [a] -> [a]
++ (case Email -> Either Template Message
email_message Email
email of
Left Template
temp ->
[ Key
"template_uuid" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Template -> UUID
template_id Template
temp
, Key
"template_variables" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Template -> Object
template_variables Template
temp
]
Right Message
msg ->
[ Key
"subject" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Message -> Text
message_subject Message
msg
, Key
"category" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Message -> Text
message_category Message
msg
] forall a. [a] -> [a] -> [a]
++ (case Message -> EmailBody
message_body Message
msg of
PlainTextBody Text
t -> [ Key
"text" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Text
t ]
HTMLOnlyBody Html
h -> [ Key
"html" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Html -> Text
renderHtml Html
h ]
HTMLBody Html
h Text
t -> [ Key
"html" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Html -> Text
renderHtml Html
h, Key
"text" forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Text
t ]
)
)
newtype InboxID = InboxID Int deriving (InboxID -> InboxID -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: InboxID -> InboxID -> Bool
$c/= :: InboxID -> InboxID -> Bool
== :: InboxID -> InboxID -> Bool
$c== :: InboxID -> InboxID -> Bool
Eq, Int -> InboxID -> ShowS
[InboxID] -> ShowS
InboxID -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [InboxID] -> ShowS
$cshowList :: [InboxID] -> ShowS
show :: InboxID -> String
$cshow :: InboxID -> String
showsPrec :: Int -> InboxID -> ShowS
$cshowsPrec :: Int -> InboxID -> ShowS
Show, Value -> Parser [InboxID]
Value -> Parser InboxID
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [InboxID]
$cparseJSONList :: Value -> Parser [InboxID]
parseJSON :: Value -> Parser InboxID
$cparseJSON :: Value -> Parser InboxID
FromJSON)
data Inbox = Inbox
{ Inbox -> InboxID
inbox_id :: InboxID
, Inbox -> Text
inbox_name :: Text
, Inbox -> Int
inbox_emailCount :: Int
, Inbox -> Int
inbox_unreadCount :: Int
, Inbox -> Int
inbox_maxSize :: Int
} deriving Int -> Inbox -> ShowS
[Inbox] -> ShowS
Inbox -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Inbox] -> ShowS
$cshowList :: [Inbox] -> ShowS
show :: Inbox -> String
$cshow :: Inbox -> String
showsPrec :: Int -> Inbox -> ShowS
$cshowsPrec :: Int -> Inbox -> ShowS
Show
instance FromJSON Inbox where
parseJSON :: Value -> Parser Inbox
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
JSON.withObject String
"Inbox" forall a b. (a -> b) -> a -> b
$ \Object
o -> InboxID -> Text -> Int -> Int -> Int -> Inbox
Inbox
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"id"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"name"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"emails_count"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"emails_unread_count"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"max_size"
getInboxes :: Token -> AccountID -> IO [Inbox]
getInboxes :: Token -> AccountID -> IO [Inbox]
getInboxes Token
token (AccountID Int
i) =
let path :: ByteString
path = forall a. IsString a => String -> a
fromString forall a b. (a -> b) -> a -> b
$ String
"/api/accounts/" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
i forall a. [a] -> [a] -> [a]
++ String
"/inboxes"
in forall err a b.
(FromJSON err, ToJSON a, FromJSON b) =>
ByteString
-> ByteString
-> ByteString
-> Token
-> (Int -> err -> Exception)
-> Maybe a
-> IO b
genericQuery ByteString
"GET" ByteString
"mailtrap.io" ByteString
path Token
token Int -> JSONResp "error" Text -> Exception
singleError Maybe ()
noBody
newtype InboxMessageID = InboxMessageID Int deriving (InboxMessageID -> InboxMessageID -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: InboxMessageID -> InboxMessageID -> Bool
$c/= :: InboxMessageID -> InboxMessageID -> Bool
== :: InboxMessageID -> InboxMessageID -> Bool
$c== :: InboxMessageID -> InboxMessageID -> Bool
Eq, Int -> InboxMessageID -> ShowS
[InboxMessageID] -> ShowS
InboxMessageID -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [InboxMessageID] -> ShowS
$cshowList :: [InboxMessageID] -> ShowS
show :: InboxMessageID -> String
$cshow :: InboxMessageID -> String
showsPrec :: Int -> InboxMessageID -> ShowS
$cshowsPrec :: Int -> InboxMessageID -> ShowS
Show, Value -> Parser [InboxMessageID]
Value -> Parser InboxMessageID
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [InboxMessageID]
$cparseJSONList :: Value -> Parser [InboxMessageID]
parseJSON :: Value -> Parser InboxMessageID
$cparseJSON :: Value -> Parser InboxMessageID
FromJSON)
data InboxMessage = InboxMessage
{ InboxMessage -> InboxMessageID
inboxMessage_id :: InboxMessageID
, InboxMessage -> InboxID
inboxMessage_inbox :: InboxID
, InboxMessage -> UTCTime
inboxMessage_sentAt :: UTCTime
, InboxMessage -> EmailAddress
inboxMessage_from :: EmailAddress
, InboxMessage -> EmailAddress
inboxMessage_to :: EmailAddress
, InboxMessage -> Text
inboxMessage_subject :: Text
, InboxMessage -> Bool
inboxMessage_isRead :: Bool
} deriving Int -> InboxMessage -> ShowS
[InboxMessage] -> ShowS
InboxMessage -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [InboxMessage] -> ShowS
$cshowList :: [InboxMessage] -> ShowS
show :: InboxMessage -> String
$cshow :: InboxMessage -> String
showsPrec :: Int -> InboxMessage -> ShowS
$cshowsPrec :: Int -> InboxMessage -> ShowS
Show
instance FromJSON InboxMessage where
parseJSON :: Value -> Parser InboxMessage
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
JSON.withObject String
"InboxMessage" forall a b. (a -> b) -> a -> b
$ \Object
o -> InboxMessageID
-> InboxID
-> UTCTime
-> EmailAddress
-> EmailAddress
-> Text
-> Bool
-> InboxMessage
InboxMessage
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"id"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"inbox_id"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"sent_at"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (EmailAddressJSON -> EmailAddress
fromEmailAddressJSON forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"from_email")
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (EmailAddressJSON -> EmailAddress
fromEmailAddressJSON forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"to_email")
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"subject"
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"is_read"
getInboxMessages :: Token -> AccountID -> InboxID -> IO [InboxMessage]
getInboxMessages :: Token -> AccountID -> InboxID -> IO [InboxMessage]
getInboxMessages Token
token (AccountID Int
accid) (InboxID Int
inboxid) =
let path :: ByteString
path = forall a. IsString a => String -> a
fromString forall a b. (a -> b) -> a -> b
$ String
"/api/accounts/" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
accid
forall a. [a] -> [a] -> [a]
++ String
"/inboxes/" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
inboxid forall a. [a] -> [a] -> [a]
++ String
"/messages"
in forall err a b.
(FromJSON err, ToJSON a, FromJSON b) =>
ByteString
-> ByteString
-> ByteString
-> Token
-> (Int -> err -> Exception)
-> Maybe a
-> IO b
genericQuery ByteString
"GET" ByteString
"mailtrap.io" ByteString
path Token
token Int -> JSONResp "error" Text -> Exception
singleError Maybe ()
noBody
downloadMessageGeneric
:: String
-> Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageGeneric :: String
-> Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageGeneric String
ext Token
token (AccountID Int
accid) (InboxID Int
inboxid) (InboxMessageID Int
msgid) =
let path :: ByteString
path = forall a. IsString a => String -> a
fromString forall a b. (a -> b) -> a -> b
$ String
"/api/accounts/" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
accid
forall a. [a] -> [a] -> [a]
++ String
"/inboxes/" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
inboxid
forall a. [a] -> [a] -> [a]
++ String
"/messages/" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
msgid
forall a. [a] -> [a] -> [a]
++ String
"/body." forall a. [a] -> [a] -> [a]
++ String
ext
in ByteString -> Text
decodeUtf8 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ByteString -> ByteString -> Token -> IO ByteString
genericDownload ByteString
"mailtrap.io" ByteString
path Token
token
downloadMessageRaw :: Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageRaw :: Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageRaw = String
-> Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageGeneric String
"raw"
downloadMessageEML :: Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageEML :: Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageEML = String
-> Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageGeneric String
"eml"
downloadMessageText :: Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageText :: Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageText = String
-> Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageGeneric String
"txt"
downloadMessageHTML :: Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageHTML :: Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageHTML = String
-> Token -> AccountID -> InboxID -> InboxMessageID -> IO Text
downloadMessageGeneric String
"html"
newtype MessageID = MessageID UUID deriving (MessageID -> MessageID -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MessageID -> MessageID -> Bool
$c/= :: MessageID -> MessageID -> Bool
== :: MessageID -> MessageID -> Bool
$c== :: MessageID -> MessageID -> Bool
Eq, Int -> MessageID -> ShowS
[MessageID] -> ShowS
MessageID -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [MessageID] -> ShowS
$cshowList :: [MessageID] -> ShowS
show :: MessageID -> String
$cshow :: MessageID -> String
showsPrec :: Int -> MessageID -> ShowS
$cshowsPrec :: Int -> MessageID -> ShowS
Show, Value -> Parser [MessageID]
Value -> Parser MessageID
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [MessageID]
$cparseJSONList :: Value -> Parser [MessageID]
parseJSON :: Value -> Parser MessageID
$cparseJSON :: Value -> Parser MessageID
FromJSON)
sendEmail :: Token -> Email -> IO [MessageID]
sendEmail :: Token -> Email -> IO [MessageID]
sendEmail = forall a. FromJSON a => Maybe InboxID -> Token -> Email -> IO [a]
genericSendEmail forall a. Maybe a
Nothing
sendTestEmail :: Token -> InboxID -> Email -> IO [InboxMessageID]
sendTestEmail :: Token -> InboxID -> Email -> IO [InboxMessageID]
sendTestEmail Token
token InboxID
i = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. AsText a -> a
asText) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. FromJSON a => Maybe InboxID -> Token -> Email -> IO [a]
genericSendEmail (forall a. a -> Maybe a
Just InboxID
i) Token
token
genericSendEmail :: FromJSON a => Maybe InboxID -> Token -> Email -> IO [a]
genericSendEmail :: forall a. FromJSON a => Maybe InboxID -> Token -> Email -> IO [a]
genericSendEmail Maybe InboxID
minbox Token
token Email
email =
let url :: ByteString
url = case Maybe InboxID
minbox of
Maybe InboxID
Nothing -> ByteString
"send.api.mailtrap.io"
Maybe InboxID
_ -> ByteString
"sandbox.api.mailtrap.io"
path :: ByteString
path = case Maybe InboxID
minbox of
Just (InboxID Int
i) -> forall a. IsString a => String -> a
fromString forall a b. (a -> b) -> a -> b
$ String
"/api/send/" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
i
Maybe InboxID
Nothing -> ByteString
"/api/send"
in forall (k :: Symbol) a. JSONResp k a -> a
fromJSONResp @"message_ids" forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall err a b.
(FromJSON err, ToJSON a, FromJSON b) =>
ByteString
-> ByteString
-> ByteString
-> Token
-> (Int -> err -> Exception)
-> Maybe a
-> IO b
genericQuery ByteString
"POST" ByteString
url ByteString
path Token
token Int -> JSONResp "errors" [Text] -> Exception
multipleErrors (forall a. a -> Maybe a
Just Email
email)