{-# LANGUAGE OverloadedStrings #-} {- | Description: low-level SMTP communciation. -} module Network.Mail.SMTP.SMTPRaw ( SMTPRaw(..) , smtpConnect , smtpSendCommand , smtpSendCommandAndWait , smtpSendRaw , smtpGetReplyLines , smtpDisconnect ) where import qualified Data.ByteString as B import Data.ByteString.Char8 (pack, unpack) import Network import Network.Socket import Data.Attoparsec.ByteString.Char8 import System.IO import Network.Mail.SMTP.ReplyLine import Network.Mail.SMTP.Types -- | An SMTPRaw has arbitrary push/pull/close methods, and ALWAYS a Handle, -- but that Handle is not assumed to be the direct means by which we push -- pull or close. This is for STARTTLS support. data SMTPRaw = SMTPRaw { smtpPush :: B.ByteString -> IO () , smtpPull :: IO B.ByteString , smtpClose :: IO () , smtpHandle :: Handle } -- | Try to open an SMTPRaw, taking the server greeting as well. -- No exception handling is performed. smtpConnect :: String -> Int -> IO (SMTPRaw, Maybe Greeting) smtpConnect host port = do handle <- connectTo host (PortNumber $ fromIntegral port) greet <- parseWith (B.hGetSome handle 2048) greeting "" let push = B.hPut handle let pull = B.hGetSome handle 2048 let close = hClose handle return $ (SMTPRaw push pull close handle, maybeResult greet) -- | Send an SMTP command and wait for the reply. -- You get Nothing in case the reply does not parse. -- No exception handling is performed. smtpSendCommandAndWait :: SMTPRaw -> Command -> IO (Maybe [ReplyLine]) smtpSendCommandAndWait smtpraw cmd = do smtpSendCommand smtpraw cmd smtpGetReplyLines smtpraw -- | Send an SMTP command. -- No exception handling is performed. smtpSendCommand :: SMTPRaw -> Command -> IO () smtpSendCommand smtpraw cmd = do smtpSendRaw smtpraw (toByteString cmd) smtpSendRaw smtpraw (pack "\r\n") -- | Send a raw byte string. Use with care. No exception handling is performed. smtpSendRaw :: SMTPRaw -> B.ByteString -> IO () smtpSendRaw = smtpPush -- | Try to read ReplyLines from the SMTPRaw. -- No exception handling is performed. smtpGetReplyLines :: SMTPRaw -> IO (Maybe [ReplyLine]) smtpGetReplyLines smtpraw = do replies <- parseWith (smtpPull smtpraw) replyLines "" return $ maybeResult replies -- | Close an SMTPRaw handle -- Be sure not to use the SMTPHandle after this. smtpDisconnect :: SMTPRaw -> IO () smtpDisconnect = smtpClose