如何正确接受 SMTP 邮件

How to properly accept a SMTP message

我想设置一个简单的 SMTP 服务器,我正在使用 Net.Mail.SmtpClient 发送邮件。一切正常,除非您下次发送消息。一旦服务器接受 TCP 客户端,然后 SMTP 客户端就会抛出错误。它说服务器违反了协议,响应正常。异常不会阻止消息通过。它只是不干净,我想了解为什么会这样。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim smtpMail As New Net.Mail.SmtpClient
    Dim msg As New Net.Mail.MailMessage
    With smtpMail
        .UseDefaultCredentials = False
        .Port = 25
        .EnableSsl = False
        .Host = "127.0.0.1"
    End With
    With msg
        .From = New MailAddress("me@test.com")
        .To.Add("lookup@test.com")
        .Subject = "Subject"
        .Body = "Body"
    End With
    smtpMail.Send(msg)
End Sub

我的服务器在上面的 Sub 之后通过 运行:

  1. EHLO(“250 正常”)
  2. 邮件(“250 OK”)
  3. RCPT(用户找到后显示“250 OK”。)
  4. DATA("354开始邮件输入;以.结尾")
  5. MIME(“250 OK”)
  6. BODY(“250 OK”)

在 BODY 命令之后,我没有得到进一步的响应。

        While True

        Dim handler As TcpClient = _Listener.AcceptTcpClient()


        Dim smtpReady() As Byte = Encoding.ASCII.GetBytes("220 Test SMTP Service ready" & vbCrLf)
        handler.GetStream().Write(smtpReady, 0, smtpReady.Length)
        Dim Message As String = String.Empty
        Try
            While True
                bytes = New Byte(1024) {}
                Dim bytesRec As Integer = handler.GetStream().Read(bytes, 0, bytes.Length)
                dta = Encoding.ASCII.GetString(bytes, 0, bytesRec)

                Dim CMD As String = dta.Substring(0, 4).ToUpper
                Dim ReturnCMD() As Byte = Nothing
                Select Case CMD
                    Case HELLO
                        ReturnCMD = Encoding.ASCII.GetBytes("250 OK" & vbCrLf)
                        handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                    Case MAIL
                        ReturnCMD = Encoding.ASCII.GetBytes("250 OK" & vbCrLf)
                        handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                    Case RECIPIENT
                        Dim SentTo As String = dta.Substring(8).Trim
                        If SentTo.ToLower <> "<lookup@test.com>" Then
                            ReturnCMD = Encoding.ASCII.GetBytes("550 No such user here" & vbCrLf)
                            handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                        Else
                            ReturnCMD = Encoding.ASCII.GetBytes("250 OK" & vbCrLf)
                            handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                        End If
                    Case data
                        ReturnCMD = Encoding.ASCII.GetBytes("354 Start mail input; end with ." & vbCrLf)
                        handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                    Case QUIT
                        ReturnCMD = Encoding.ASCII.GetBytes("221 Service closing transmission channel" & vbCrLf)
                        handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                        Exit While
                    Case RESET
                        ReturnCMD = Encoding.ASCII.GetBytes("221 Service closing transmission channel" & vbCrLf)
                        handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                        Exit While
                    Case EHELLO
                        ReturnCMD = Encoding.ASCII.GetBytes("250 OK" & vbCrLf)
                        handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                    Case MIME
                        ReturnCMD = Encoding.ASCII.GetBytes("250 OK" & vbCrLf)
                        handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                    Case BODY
                        Message += dta
                        RaiseEvent DataReceived(Message)
                        ReturnCMD = Encoding.ASCII.GetBytes("250 OK" & vbCrLf)
                        handler.GetStream().Write(ReturnCMD, 0, ReturnCMD.Length)
                End Select

            End While

            handler.Close()
        Catch ex As Exception
        End Try
    End While

代码可能有些 redundancy/is 混乱。到目前为止,这只是对其他东西的测试。我只是想了解 SMTP。

调用 SmtpClient.Dispose 解决了我的问题。这会向服务器发送 QUIT,并正常关闭连接。

由于关闭连接似乎是问题所在,因此在您的 SMTP 客户端周围添加一个 Using 块可能会有用。 Using 就像一个 try-catch 一样,在它到达关闭 End Using -

时安全地关闭和处理任何资源连接
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Using smtpMail As New Net.Mail.SmtpClient
        Using msg As New Net.Mail.MailMessage
            With smtpMail
                .UseDefaultCredentials = False
                .Port = 25
                .EnableSsl = False
                .Host = "127.0.0.1"
            End With
            With msg
                .From = New MailAddress("me@test.com")
                .To.Add("lookup@test.com")
                .Subject = "Subject"
                .Body = "Body"
            End With
            smtpMail.Send(msg)
        End Using
    End Using
End Sub