2012-07-03 17 views
9

Ich versuche, ein einfaches Skript zu schreiben, um eine Mail über meine Google Mail-Konto zu senden. Aber ich bin ein Anfänger, also ist es nicht so einfach. Ich habe versucht Google aber außer für Hacker, gibt es keine Hilfe oder Beispiele.Verwenden von TLS-Extra für einfache SMTP

Das Problem ist, dass ich nicht die Möglichkeit gefunden habe, tls-extra (oder tls) zu verwenden, um den STARTTLS-Austausch zu initiieren.

Ok, hier ist der Code:

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 

Eine andere Sache ist, dass ich die Funktion hören verwenden zu wissen, was los ist. Aber ich kann nicht herausfinden, wie man es zusammen mit Schreiben verwendet. Das heißt, ich würde gerne sehen, was auf der Serverseite passiert, während ich Daten sende.

fand ich zwei Funktionen, die meine Probleme lösen können:

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

Die erste für tls und die zweite zu senden und gleichzeitig zu empfangen. Aber kann nicht scheinen, dass sie funktionieren.

Ich hoffe, ich bin hier nicht unordentlich, jede Hilfe wäre willkommen.

PS: Englisch ist nicht meine Muttersprache.

EDIT: Also, ich habe ein paar Fortschritte gemacht.

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 

Noch kann ich nicht herausfinden, wie man diesen tls Händedruck aushandelt.

Ich muss sagen, ich bin ziemlich überrascht von der fehlenden Antwort. Die anderen Male hatte ich ein Problem, die Gemeinde war ziemlich schnell zu helfen. Aber das scheint nicht zu interessieren (nur eine Konstration). Hier bei SO oder sogar bei #haskell oder entwickepez.com.

Anyway einige Hinweise über Google und Tls wäre willkommen. Ich habe mir den msmtp-Client-Code angeschaut, aber offen gesagt, habe ich nicht das erforderliche Level.

+0

Ich habe genau dasselbe Problem. Hast du es geschafft, es herauszufinden? – Salil

+0

Nicht wirklich relevant für Ihre Frage, aber lassen Sie mich darauf hinweisen, dass 'forever' in den Basisbibliotheken definiert ist. Siehe [Hackage] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Monad.html#v:forever). –

Antwort

5

Sie können das Verbindungspaket verwenden, das die Verbindung mit dem Client vereinfacht und alle erforderlichen Bits dafür bereitstellt. Der folgende Code funktioniert, um eine Verbindung zu smtp.gmail.com herzustellen:

{-# 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

Hatte bereits funktionierenden Code, wenn Sie veröffentlicht, aber Ihr Code ist sauberer.Jedenfalls nur ein Update, um zu sagen, dass ich seitdem jede native Code-Lösung fallen gelassen habe und nur einen benutzerdefinierten Wrapper um den Msmtp-Befehl benutze, der auf DOS und NIX verfügbar ist und sich bereits mit allem beschäftigt, was Sie wollen. – Sarfraz

1

Ich weiß nicht genau, was das Problem verursacht, das Sie haben (Mein SMTP ist ein wenig eingerostet), aber ich glaube, dass ein Teil des Problems darin besteht, dass Sie eine Verbindung auf dem falschen Port herstellen. Ich denke, das sind die richtigen Parameter für die Verwendung von SMTP mit Google.

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 

bearbeiten: Ich habe eine schnelle Suche von Hackage tat, um zu sehen, ob es ein SMTP-Paket war, das Sie mit einem Benutzernamen und Passwort, mit TLS/SSL anmelden erlauben würde, aber ich habe nichts gesehen. (Ich hätte allerdings etwas übersehen können!) Der nächste, den ich gefunden habe, war simplesmtpclient. Ich denke nicht, dass es SSL unterstützt, aber vielleicht könnten Sie das erweitern oder es als Anleitung zum Schreiben Ihrer eigenen verwenden.