9

我正在尝试编写一个简单的脚本来通过我的 gmail 帐户发送邮件。但我是初学者,所以没那么简单。我尝试了谷歌,但除了hackage,根本没有帮助或示例。

问题是我没有找到使用 tls-extra(或 tls)来启动 STARTTLS 交换的方法。

好的,代码如下:

import Network
import Network.TLS.Extra
import System.IO
import Text.Printf

server = "smtp.gmail.com"
port   = 25 --that has to chage, I think

forever a = a >> forever a

main = test1

write :: Handle -> String -> IO ()
write h s  = do
    hPrintf h "%s\r\n" s
    printf    "> %s\n" s

listen :: Handle -> IO () 
listen h = forever $ hGetLine h >>= putStrLn

test1 = do h <- connectTo server (PortNumber (fromIntegral port))
           hSetBuffering h NoBuffering
           write h "EHLO"
           write h "STARTTLS"
           listen h

另一件事是我使用监听功能来了解发生了什么。但我不知道如何将它与 write 一起使用。也就是说,我希望能够在发送一些数据时看到服务器端发生了什么。

我发现了两个可以解决我的问题的功能:

connectionClient :: CryptoRandomGen g => String -> String -> TLSParams -> g -> IO (TLSCtx Handle)
forkIO :: IO () -> IO ThreadId

第一个用于 tls,第二个用于同时发送和接收。但似乎无法让它们工作。

我希望我不会在这里弄乱,任何帮助将不胜感激。

PS:英语不是我的母语。

编辑:所以,我取得了一些进展。

import Network
import Network.TLS
import Network.TLS.Extra
import System.IO
import Text.Printf
import Control.Monad (forever)
import Control.Concurrent (threadDelay)
import qualified Data.ByteString.Char8 as B
import Crypto.Random

serv :: String
serv = "smtp.gmail.com"
port :: Int
port   = 25 --that has to chage, I think

main :: IO ()
main = test1

write :: Handle -> String -> IO ()
write h s  = do
    hPrintf h "%s\r\n" s
    printf    "> %s\n" s

listen :: Handle -> IO ()
listen h = forever $ hGetLine h >>= putStrLn

printSock :: Handle -> String -> IO ()
printSock h s = do write h s
                   hGetLine h >>= putStrLn
                   threadDelay 25

params :: TLSParams
params=defaultParams {pConnectVersion=TLS12
                     ,pAllowedVersions=[TLS10, TLS11, TLS12]
                     ,pCiphers=ciphersuite_all}

test1 = do h <- connectTo serv (PortNumber (fromIntegral port))
           hSetBuffering h NoBuffering
           printSock h "EHLO"
           printSock h "STARTTLS"
           --google waits for tls handshake
           --the problem is from here
           g <- newGenIO :: IO SystemRandom
           tlsH <- client params g h
           handshake tlsH --the handshake is failling

不过,我不知道如何协商 tls 握手。

我不得不说,我对没有答案感到非常惊讶。其他几次我遇到了问题,社区很快就提供了帮助。但这似乎并不感兴趣(只是一种说法)。在 SO 或什至在#haskell 或developpez.com。

无论如何,一些关于谷歌和 tls 的指针将受到欢迎。我查看了 msmtp 客户端代码,但坦率地说,我没有所需的级别。

4

2 回答 2

5

您可以使用连接包来简化客户端连接并为此提供所有必要的位。以下代码可用于连接到 smtp.gmail.com:

{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString as B
import Data.ByteString.Char8 ()
import Network.Connection
import Data.Default

readHeader con = do
    l <- connectionGetLine 1024 con
    putStrLn $ show l
    if B.isPrefixOf "250 " l
        then return ()
        else readHeader con

main = do
    ctx <- initConnectionContext
    con <- connectTo ctx $ ConnectionParams
                            { connectionHostname  = "smtp.gmail.com"
                            , connectionPort      = 25
                            , connectionUseSecure = Nothing
                            , connectionUseSocks  = Nothing
                            }

    -- read the server banner
    connectionGetLine 1024 con >>= putStrLn . show
    -- say ehlo to the smtp server
    connectionPut con "EHLO\n"
    -- wait for a reply and print
    readHeader con
    -- Tell the server to start a TLS context.
    connectionPut con "STARTTLS\n"
    -- wait for a reply and print
    connectionGetLine 1024 con >>= putStrLn . show

    -- negociate the TLS context
    connectionSetSecure ctx con def

    ------- connection is secure now
    -- send credential, passwords, ask question, etc.

    -- then quit politely.
    connectionPut con "QUIT\n"
    connectionClose con
于 2013-05-06T06:15:55.997 回答
1

我不知道究竟是什么导致了您遇到的问题(我的 SMTP 有点生锈),但我相信部分问题是您连接到错误的端口。我认为这些是在 Google 中使用 SMTP 的正确参数。

Gmail SMTP server address: smtp.gmail.com
Gmail SMTP user name: Your full Gmail address (e.g. example@gmail.com)
Gmail SMTP password: Your Gmail password
Gmail SMTP port: 465
Gmail SMTP TLS/SSL required: yes 

编辑:我快速搜索了 Hackage,看看是否有一个 SMTP 包可以让你使用 TLS/SSL 使用用户名和密码登录,但我什么也没看到。(不过,我可能忽略了一些事情!)我找到的最接近的是 simplesmtpclient。我认为它不支持 SSL,但也许您可以扩展它,或者将其用作编写自己的指南。

于 2012-10-17T15:05:12.627 回答