2012-07-03 70 views
9

我正在嘗試編寫一個簡單的腳本來通過我的gmail帳戶發送郵件。但我是初學者,所以不是那麼簡單。我嘗試谷歌,但免除了駭客,沒有任何幫助或例子。使用tls-extra用於簡單的smtp

的問題是,我沒有找到使用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 

另一件事是,我用聽的功能就知道是怎麼回事。但我無法弄清楚如何將它與寫入一起使用。也就是說,我希望在發送某些數據時能夠看到服務器端發生了什麼。

我發現可以解決我的問題有兩個功能:

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客戶端代碼,但坦率地說我沒有所需的級別。

+0

我有完全相同的問題。你設法弄清楚了嗎? – Salil

+0

與你的問題沒有太大的關係,但讓我指出'永遠'是在基礎庫中定義的。參見[Hackage](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Monad.html#v:forever)。 –

回答

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 
+0

當您發佈但您的代碼更清潔時,已經有工作代碼。無論如何,只是一個更新說,從那時起我放棄了任何本地代碼解決方案,並且只是使用一個自定義的包裝在msmtp命令,這是在dos和nix上可用,並已經處理任何你想要的。 – Sarfraz

1

我不知道到底是什麼導致你有(我的SMTP是有點生疏)的問題,但我認爲問題的一部分是,你連接了錯誤的端口上。我認爲這些是與Google一起使用SMTP的正確參數。

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

編輯:我做了快速搜索Hackage,看看是否有一個SMTP包,它會讓你的用戶名和密碼,使用TLS/SSL登錄,但我什麼也沒看見。 (儘管我可能忽略了某些東西!)我發現的最接近的是simplesmtpclient。我不認爲它支持SSL,但也許你可以擴展它,或者將它用作編寫自己的指南。