对简单的smtp使用tls-extra [英] Using tls-extra for simple smtp

查看:114
本文介绍了对简单的smtp使用tls-extra的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图编写一个简单的脚本来通过我的Gmail账户发送邮件。但我是初学者,所以不是那么简单。我尝试谷歌,但免除了骇客,根本没有帮助或例子。



问题是我没有找到使用tls-extra(或tls )开始STARTTLS交换。



好的,这里是代码:

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

server =smtp.gmail.com
port = 25 - 必须chage,我认为

forever a = a>>永远是

main = test1

write :: Handle - >字符串 - > IO()
写入hs = do
hPrintf h%s\r\\\
s
printf>%s \ ns

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

test1 = do h < - connectTo server(PortNumber(fromIntegral port))
hSetBuffering h NoBuffering
写hEHLO
写hSTARTTLS
听h


$ b $另一件事是我使用listen函数来了解正在发生的事情。但我无法弄清楚如何将它与写入一起使用。也就是说,我希望能够在发送一些数据时看到服务器端发生了什么。



我发现了两个可能解决我的问题的函数:

  connectionClient :: CryptoRandomGen g =>字符串 - >字符串 - > TLSParams  - > g  - > IO(TLSCtx句柄)
forkIO :: IO() - > IO ThreadId

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



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



PS:英文不是我的母语。



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

  import Network 
import Network.TLS
import Network.TLS.Extra
import System.IO
导入Text.Printf
导入Control.Monad(永久)
导入Control.Concurrent(threadDelay)
将合格的Data.ByteString.Char8导入为B
import Crypto.Random

serv :: String
serv =smtp.gmail.com
port :: Int
port = 25 - 必须变动,我认为

main :: IO()
main = test1

write :: Handle - >字符串 - > IO()
写入hs = do
hPrintf h%s\r\\\
s
printf>%s \ ns

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

printSock :: Handle - >字符串 - > IO()
printSock hs =写入hs
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 hEHLO
printSock hSTARTTLS
--google等待握手
- 问题出在这里
g< - newGenIO :: IO SystemRandom
tlsH< - client params gh
handshake tlsH - 握手失败

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



我不得不说,我很惊讶缺乏答案。其他人几次遇到问题,社区很快就会提供帮助。但是这似乎没有意义(只是一个常式)。在SO或甚至在#haskell或developpez.com。



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

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

  { - #LANGUAGE OverloadedStrings# - } 
将合格的Data.ByteString导入为B
import Data.ByteString.Char8()
import Network.Connection
import Data.Default

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

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

- 读取服务器标题
connectionGetLine 1024 con>>> = putStrLn。显示
- 说ehlo到smtp服务器
connectionPut conEHLO \\\

- 等待回复并打印
readHeader con
- Tell服务器启动一个TLS上下文。
connectionPut conSTARTTLS\\\

- 等待回复并打印
connectionGetLine 1024 con>> = putStrLn。显示

- 关联TLS上下文
connectionSetSecure ctx con def

-------连接现在是安全的
- 发送凭据,密码,问问题等。

- 然后礼貌地退出。
connectionPut conQUIT\\\

connectionClose con


I am trying to write a simple script to send a mail via my gmail account. But I am a beginner so it is not that simple. I tryed google but exept for hackage, there is no help or examples at all.

The problem is that I did not find the way to use tls-extra(or tls) to initiate the STARTTLS exchange.

Ok, here is the 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

Another thing is that I use the listen function to know what is going on. But I cannot figure out how to use it along with write. That is to say, I would like to be able to see what is going on server-side while sending some data.

I found two functions that may resolve my problems:

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

The first for tls and the second to send and receive at the same time. But can't seem to make them work.

I hope I am not to messy here, any help would be appreciated.

PS: English is not my native.

EDIT: So, I have made some progress.

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

Still, I cannot figure out how to negotiate that tls handshake.

I have to say, I am quite surprised by the lack of answer. The others few times I had a problem, the community was quite quick to help. But this doesn't seem to interess (just a constatation). Here at SO or even at #haskell or developpez.com.

Anyways some pointers about google and tls would be welcome. I have taken a look at the msmtp client code but frankly I don't have the required level.

解决方案

You could use the connection package which simplify client connection and provide all the necessary bits for this. The following code will works to connect to 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

这篇关于对简单的smtp使用tls-extra的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆