-----------------------------------------------------------------------------
-- |
-- Module      :  Network.SMTP.Simple
-- Copyright   :  2009 Matthew Elder
-- License     :  BSD3
--
-- Maintainer  :  Matthew Elder
-- Stability   :  provisional
-- Portability :  linux/windows
--
-- Mail is a simple library with which you can add email functionality to your
-- application. It assumes you have access to a smarthost which can relay all
-- your mail.
-- 
-- As an example:
--
-- > import Network.SMTP.Simple
-- > import System.IO
-- >
-- > main :: IO ()
-- > main = do
-- >     sendSimpleMessages (hPutStrLn stderr) "10.2.23.11" "example.com" [message]
-- >     where message = SimpleMessage
-- >                         [NameAddr (Just "John Doe") "johnd@example.com"]
-- >                         [NameAddr (Just "Team") "team@exmaple.com"]
-- >                         "My test email using Network.SMTP.Simple"
-- >                         "Hi, this is a test email which uses SMTPClient."

module Network.SMTP.Simple
    ( NameAddr(..)
    , SimpleMessage(..)
    , sendRawMessages
    , sendSimpleMessages
    ) where

import Data.IORef (newIORef, readIORef)
import Network.Socket
    (SockAddr(..)
    , inet_addr
    )
import Network.SMTP.Client
import System.Time
    ( CalendarTime(..)
    , getClockTime
    , toCalendarTime
    )

data SimpleMessage
    = SimpleMessage
        { from :: [NameAddr] -- ^ The sender(s)
        , to :: [NameAddr]   -- ^ The recipient(s)
        , subject :: String  -- ^ The subject line
        , body :: String     -- ^ The body
        }
    deriving (Show)

toMessage :: CalendarTime -> SimpleMessage -> Message
toMessage ct sm =
    Message
        [From (from sm), To (to sm), Subject (subject sm), Date ct]
        (body sm)

-- | Simplest way to send mail.  Takes the smarthost ip, the HELO domain, and a list of SimpleMessage.
sendSimpleMessages :: (String -> IO ())  -- ^ Diagnostic log function
                   -> String          -- ^ IP address of the smarthost
                   -> String          -- ^ HELO domain (should be the same as your from-address-domain)
                   -> [SimpleMessage] -- ^ List of simple messages to send
                   -> IO ()
sendSimpleMessages log smartHostIp heloDomain simpleMessages = do
    nowCT <- toCalendarTime =<< getClockTime
    hostAddr <- inet_addr smartHostIp
    let smtpSockAddr = SockAddrInet 25 hostAddr
    sendRawMessages log smtpSockAddr heloDomain (map (toMessage nowCT) simpleMessages)

-- | Use this if you need more control than sendSimpleMessages gives you.
sendRawMessages :: (String -> IO ()) -- ^ Diagnostic log function
                -> SockAddr  -- ^ SockAddr for the smarthost
                -> String    -- ^ HELO domain (should be the same as your from-address-domain)
                -> [Message] -- ^ List of messages to send
                -> IO ()
sendRawMessages log smtpSockAddr heloDomain messages = do
    sentRef <- newIORef []
    sendSMTP' log (Just sentRef) heloDomain smtpSockAddr messages
    statuses <- readIORef sentRef
  
    -- If no exception was caught, statuses is guaranteed to be
    -- the same length as the list of input messages, therefore head won't fail here.
    case head statuses of
        Nothing ->
            return ()
        Just status ->
            log $ "message failed: " ++ show status
