sendMailTls' :: HostName -> Int -> UserName -> Password -> Mail -> IO ()
sendMailTls' host port user passwd mail = do
        g <- RNG.makeSystem
        let pn = PortNumber $ fromIntegral port
        h <- connectTo host pn
        hSetBuffering h LineBuffering

        write h "EHLO"
        waitFor h "250-STARTTLS"
        write h "STARTTLS"
        waitFor h "220"

        ctx <- contextNewOnHandle h tlsParams g
        let sendLine = tlsWrite ctx
        -- putStrLn "handshake"
        handshake ctx

        -- putStrLn "login"
        tlsWriteWait ctx ("EHLO" :: String) "250"
        tlsWriteWait ctx ("AUTH LOGIN" :: String) "334"
        tlsWriteWait ctx (b64 user) "334"
        tlsWriteWait ctx (b64 passwd) "235"

        -- putStrLn "renderAndSend"
        mailbs <- renderMail' mail
        writeAddress ctx "MAIL FROM" $ mailFrom mail
        let rcpts = concatMap (\f -> f mail) [mailTo, mailCc, mailBcc]
        forM_ rcpts $ writeAddress ctx "RCPT TO"
        tlsWriteWait ctx ("DATA" :: String) "354"

        mapM_ sendLine . concatMap BCL.toChunks $ split mailbs
        mapM_ sendLine $ BCL.toChunks dot
        tlsWaitFor ctx "250"

        -- putStrLn "bye"
        bye ctx

    where 
        split = map (padDot . stripCR) . BCL.split '\n'
        -- remove \r at the end of a line
        stripCR s = if cr `BL.isSuffixOf` s then BL.init s else s
        -- duplicate . at the start of a line
        padDot s = if dot `BL.isPrefixOf` s then dot <> s else s
        cr = BCL.pack "\r"
        dot = BCL.pack "."
sendMailTls' :: HostName -> Int -> UserName -> Password -> Mail -> IO ()
sendMailTls' host port user passwd mail = do
        g <- RNG.makeSystem
        let pn = PortNumber $ fromIntegral port
        h <- connectTo host pn
        hSetBuffering h LineBuffering

        write h "EHLO"
        waitFor h "250-STARTTLS"
        write h "STARTTLS"
        waitFor h "220"

        ctx <- contextNewOnHandle h tlsParams g
        let sendLine = tlsWrite ctx
        -- putStrLn "handshake"
        handshake ctx

        -- putStrLn "login"
        tlsWriteWait ctx ("EHLO" :: String) "250"
        tlsWriteWait ctx ("AUTH LOGIN" :: String) "334"
        tlsWriteWait ctx (b64 user) "334"
        tlsWriteWait ctx (b64 passwd) "235"

        -- putStrLn "renderAndSend"
        mailbs <- renderMail' mail
        writeAddress ctx "MAIL FROM" $ mailFrom mail
        let rcpts = concatMap (\f -> f mail) [mailTo, mailCc, mailBcc]
        forM_ rcpts $ writeAddress ctx "RCPT TO"
        tlsWriteWait ctx ("DATA" :: String) "354"

        mapM_ sendLine . concatMap BCL.toChunks $ split mailbs
        mapM_ sendLine $ BCL.toChunks dot
        tlsWaitFor ctx "250"

        -- putStrLn "bye"
        bye ctx

    where 
        split = map (padDot . stripCR) . BCL.split '\n'
        -- remove \r at the end of a line
        stripCR s = if cr `BL.isSuffixOf` s then BL.init s else s
        -- duplicate . at the start of a line
        padDot s = if dot `BL.isPrefixOf` s then dot <> s else s
        cr = BCL.pack "\r"
        dot = BCL.pack "."
sendMailTls' host port user passwd mail = do
        g <- RNG.makeSystem
        let pn = PortNumber $ fromIntegral port
        h <- connectTo host pn
        hSetBuffering h LineBuffering

        write h "EHLO"
        waitFor h "250-STARTTLS"
        write h "STARTTLS"
        waitFor h "220"

        ctx <- contextNewOnHandle h tlsParams g
        let sendLine = tlsWrite ctx
        -- putStrLn "handshake"
        handshake ctx

        -- putStrLn "login"
        tlsWriteWait ctx ("EHLO" :: String) "250"
        tlsWriteWait ctx ("AUTH LOGIN" :: String) "334"
        tlsWriteWait ctx (b64 user) "334"
        tlsWriteWait ctx (b64 passwd) "235"

        -- putStrLn "renderAndSend"
        mailbs <- renderMail' mail
        writeAddress ctx "MAIL FROM" $ mailFrom mail
        let rcpts = concatMap (\f -> f mail) [mailTo, mailCc, mailBcc]
        forM_ rcpts $ writeAddress ctx "RCPT TO"
        tlsWriteWait ctx ("DATA" :: String) "354"

        mapM_ sendLine . concatMap BCL.toChunks $ split mailbs
        mapM_ sendLine $ BCL.toChunks dot
        tlsWaitFor ctx "250"

        -- putStrLn "bye"
        bye ctx

    where 
        split = map (padDot . stripCR) . BCL.split '\n'
        -- remove \r at the end of a line
        stripCR s = if cr `BL.isSuffixOf` s then BL.init s else s
        -- duplicate . at the start of a line
        padDot s = if dot `BL.isPrefixOf` s then dot <> s else s
        cr = BCL.pack "\r"
        dot = BCL.pack "."