예제 #1
0
        /// <summary>
        /// Send the MAIL FROM command to the server using <paramref name="mailFrom"/> as parameter.
        /// </summary>
        /// <param name="mailFrom">Email address to use as parameter.</param>
        /// <param name="failedCallback">Action to call if command fails.</param>
        public async Task <bool> ExecMailFromAsync(MailAddress mailFrom, Action <string> failedCallback)
        {
            if (!base.Connected)
            {
                return(false);
            }

            _LastActive = DateTime.UtcNow;
            IsActive    = true;
            await SmtpStream.WriteLineAsync("MAIL FROM: <" +
                                            (mailFrom == null ? string.Empty : mailFrom.Address) + ">" +
                                            (_DataTransportMime == SmtpTransportMIME._8BitUTF ? " BODY=8BITMIME" : string.Empty));

            // If the remote MX doesn't support pipelining then wait and check the response.
            if (!_CanPipeline)
            {
                string response = await SmtpStream.ReadAllLinesAsync();

                if (!response.StartsWith("250"))
                {
                    failedCallback(response);
                }
            }

            _LastActive = DateTime.UtcNow;
            IsActive    = false;

            return(true);
        }
예제 #2
0
        /// <summary>
        /// Send the RCPT TO command to the server using <paramref name="rcptTo"/> as parameter.
        /// </summary>
        /// <param name="rcptTo">Email address to use as parameter.</param>
        /// <param name="failedCallback">Action to call if command fails.</param>
        public async Task <bool> ExecRcptToAsync(MailAddress rcptTo, Action <string> failedCallback)
        {
            if (!base.Connected)
            {
                return(false);
            }

            IsActive    = true;
            _LastActive = DateTime.UtcNow;
            await SmtpStream.WriteLineAsync("RCPT TO: <" + rcptTo.Address + ">");

            // If the remote MX doesn't support pipelining then wait and check the response.
            if (!_CanPipeline)
            {
                string response = await SmtpStream.ReadAllLinesAsync();

                if (!response.StartsWith("250"))
                {
                    failedCallback(response);
                }
            }

            _LastActive = DateTime.UtcNow;
            IsActive    = false;

            return(true);
        }
예제 #3
0
        /// <summary>
        /// Send the data to the server
        /// </summary>
        /// <param name="data">Data to send to the server</param>
        /// <param name="failedCallback">Action to call if fails to send.</param>
        private async Task <MantaOutboundClientSendResult> ExecDataAsync(string data)
        {
            await SmtpStream.WriteLineAsync("DATA");

            string response = await SmtpStream.ReadAllLinesAsync(); // Data response or Mail From if pipelining

            // If the remote MX supports pipelining then we need to check the MAIL FROM and RCPT to responses.
            if (_CanPipeline)
            {
                // Check MAIL FROM OK.
                if (!response.StartsWith("250"))
                {
                    await SmtpStream.ReadAllLinesAsync(); // RCPT TO

                    await SmtpStream.ReadAllLinesAsync(); // DATA

                    return(new MantaOutboundClientSendResult(MantaOutboundClientResult.RejectedByRemoteServer, response, _VirtualMta, _MXRecord));
                }


                // Check RCPT TO OK.
                response = await SmtpStream.ReadAllLinesAsync();

                if (!response.StartsWith("250"))
                {
                    await SmtpStream.ReadAllLinesAsync(); // DATA

                    return(new MantaOutboundClientSendResult(MantaOutboundClientResult.RejectedByRemoteServer, response, _VirtualMta, _MXRecord));
                }

                // Get the Data Command response.
                response = await SmtpStream.ReadAllLinesAsync();
            }

            if (!response.StartsWith("354"))
            {
                return(new MantaOutboundClientSendResult(MantaOutboundClientResult.RejectedByRemoteServer, response, _VirtualMta, _MXRecord));
            }

            // Send the message data using the correct transport MIME
            SmtpStream.SetSmtpTransportMIME(_DataTransportMime);
            await SmtpStream.WriteAsync(data, false);

            await SmtpStream.WriteAsync(MtaParameters.NewLine + "." + MtaParameters.NewLine, false);

            // Data done so return to 7-Bit mode.
            SmtpStream.SetSmtpTransportMIME(SmtpTransportMIME._7BitASCII);

            response = await SmtpStream.ReadAllLinesAsync();

            if (!response.StartsWith("250"))
            {
                return(new MantaOutboundClientSendResult(MantaOutboundClientResult.RejectedByRemoteServer, response, _VirtualMta, _MXRecord));
            }

            _MessagesAccepted++;
            return(new MantaOutboundClientSendResult(MantaOutboundClientResult.Success, response, _VirtualMta, _MXRecord));
        }
예제 #4
0
        /// <summary>
        /// Say EHLO/HELO to the server.
        /// Will also check to see if 8BITMIME is supported.
        /// </summary>
        /// <param name="failedCallback">Action to call if hello fail.</param>
        private async Task <MantaOutboundClientSendResult> ExecHeloAsync()
        {
            // We have connected to the MX, Say EHLO.
            await SmtpStream.WriteLineAsync("EHLO " + _VirtualMta.Hostname);

            string response = await SmtpStream.ReadAllLinesAsync();

            if (response.StartsWith("421"))
            {
                return(new MantaOutboundClientSendResult(MantaOutboundClientResult.ServiceNotAvalible, response, _VirtualMta, _MXRecord));
            }

            try
            {
                if (!response.StartsWith("2"))
                {
                    // If server didn't respond with a success code on hello then we should retry with HELO
                    await SmtpStream.WriteLineAsync("HELO " + _VirtualMta.Hostname);

                    response = await SmtpStream.ReadAllLinesAsync();

                    if (!response.StartsWith("250"))
                    {
                        TcpClient.Close();
                        return(new MantaOutboundClientSendResult(MantaOutboundClientResult.ServiceNotAvalible, response, _VirtualMta, _MXRecord));
                    }
                }
                else
                {
                    // Server responded to EHLO
                    // Check to see if it supports 8BITMIME
                    if (response.IndexOf("8BITMIME", StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        _DataTransportMime = SmtpTransportMIME._8BitUTF;
                    }
                    else
                    {
                        _DataTransportMime = SmtpTransportMIME._7BitASCII;
                    }

                    // Check to see if the server supports pipelining
                    _CanPipeline = response.IndexOf("PIPELINING", StringComparison.OrdinalIgnoreCase) > -1;
                }
            }
            catch (IOException)
            {
                // Remote Endpoint Disconnected Mid HELO.
                return(new MantaOutboundClientSendResult(MantaOutboundClientResult.ServiceNotAvalible, response, _VirtualMta, _MXRecord));
            }

            return(new MantaOutboundClientSendResult(MantaOutboundClientResult.Success, null, _VirtualMta, _MXRecord));
        }
예제 #5
0
        /// <summary>
        /// Send the RSET command to the server.
        /// </summary>
        public async Task <bool> ExecRsetAsync()
        {
            if (!base.Connected)
            {
                Logging.Debug("Cannot RSET connection has been closed.");
                throw new Exception();
            }
            IsActive = true;
            await SmtpStream.WriteLineAsync("RSET");

            await SmtpStream.ReadAllLinesAsync();

            _LastActive = DateTime.UtcNow;
            IsActive    = false;

            return(true);
        }
예제 #6
0
        /// <summary>
        /// Send the RCPT TO command to the server using <paramref name="rcptTo"/> as parameter.
        /// </summary>
        /// <param name="rcptTo">Email address to use as parameter.</param>
        /// <param name="failedCallback">Action to call if command fails.</param>
        private async Task <MantaOutboundClientSendResult> ExecRcptToAsync(MailAddress rcptTo)
        {
            await SmtpStream.WriteLineAsync("RCPT TO: <" + rcptTo.Address + ">");

            // If the remote MX doesn't support pipelining then wait and check the response.
            if (!_CanPipeline)
            {
                string response = await SmtpStream.ReadAllLinesAsync();

                if (!response.StartsWith("250"))
                {
                    return(new MantaOutboundClientSendResult(MantaOutboundClientResult.RejectedByRemoteServer, response, _VirtualMta, _MXRecord));
                }
            }

            return(new MantaOutboundClientSendResult(MantaOutboundClientResult.Success, null, _VirtualMta, _MXRecord));
        }
예제 #7
0
        /// <summary>
        /// Send the SMTP Quit command to the Server.
        /// </summary>
        private async Task ExecQuitAsync()
        {
            if (TcpClient.Connected)
            {
                try
                {
                    await SmtpStream.WriteLineAsync("QUIT");

                    // Don't read response as don't care.
                    // Close the TCP connection.
                    TcpClient.GetStream().Close();
                    TcpClient.Close();
                }
                catch (ObjectDisposedException)
                {
                    Logging.Debug("SmtpOutboundClient: Tried to quit an already disposed client.");
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Send the RSET command to the server.
        /// </summary>
        private async Task <MantaOutboundClientSendResult> ExecRsetAsync()
        {
            if (!await SmtpStream.WriteLineAsync("RSET"))
            {
                throw new ObjectDisposedException("Connection");
            }

            var response = await SmtpStream.ReadAllLinesAsync();

            switch (response[0])
            {
            case '2':
                return(new MantaOutboundClientSendResult(MantaOutboundClientResult.Success, response, _VirtualMta, _MXRecord));

            case '4':
            case '5':
            default:
                return(new MantaOutboundClientSendResult(MantaOutboundClientResult.RejectedByRemoteServer, response, _VirtualMta, _MXRecord));
            }
        }
예제 #9
0
        /// <summary>
        /// Send the SMTP Quit command to the Server.
        /// </summary>
        public async Task <bool> ExecQuitAsync()
        {
            if (!base.Connected)
            {
                return(false);
            }

            IsActive = true;
            try
            {
                await SmtpStream.WriteLineAsync("QUIT");

                // Don't read response as don't care.
                // Close the TCP connection.
                base.GetStream().Close();
                base.Close();
            }
            catch (ObjectDisposedException) {
                Logging.Debug("SmtpOutboundClient: Tried to quit an already disposed client.");
            }
            IsActive = false;
            return(true);
        }
예제 #10
0
        /// <summary>
        /// Send the MAIL FROM command to the server using <paramref name="mailFrom"/> as parameter.
        /// </summary>
        /// <param name="mailFrom">Email address to use as parameter.</param>
        /// <param name="failedCallback">Action to call if command fails.</param>
        private async Task <MantaOutboundClientSendResult> ExecMailFromAsync(MailAddress mailFrom)
        {
            await SmtpStream.WriteLineAsync("MAIL FROM: <" +
                                            (mailFrom == null ? string.Empty : mailFrom.Address) + ">" +
                                            (_DataTransportMime == SmtpTransportMIME._8BitUTF ? " BODY=8BITMIME" : string.Empty));

            // If the remote MX doesn't support pipelining then wait and check the response.
            if (!_CanPipeline)
            {
                string response = await SmtpStream.ReadAllLinesAsync();

                if (!response.StartsWith("250"))
                {
                    if (response.StartsWith("421"))
                    {
                        return(new MantaOutboundClientSendResult(MantaOutboundClientResult.ServiceNotAvalible, response, _VirtualMta, _MXRecord));
                    }

                    return(new MantaOutboundClientSendResult(MantaOutboundClientResult.RejectedByRemoteServer, response, _VirtualMta, _MXRecord));
                }
            }

            return(new MantaOutboundClientSendResult(MantaOutboundClientResult.Success, null, _VirtualMta, _MXRecord));
        }
예제 #11
0
        /// <summary>
        /// Say EHLO/HELO to the server.
        /// Will also check to see if 8BITMIME is supported.
        /// </summary>
        /// <param name="failedCallback">Action to call if hello fail.</param>
        public async Task <bool> ExecHeloAsync(Action <string> failedCallback)
        {
            if (!base.Connected)
            {
                return(false);
            }

            _LastActive = DateTime.UtcNow;
            IsActive    = true;

            // We have connected to the MX, Say EHLO.
            _LastActive = DateTime.UtcNow;
            await SmtpStream.WriteLineAsync("EHLO " + MtaIpAddress.Hostname);

            string response = await SmtpStream.ReadAllLinesAsync();

            if (response.StartsWith("421"))
            {
                failedCallback(response);
            }
            _LastActive = DateTime.UtcNow;

            try
            {
                if (!response.StartsWith("2"))
                {
                    // If server didn't respond with a success code on hello then we should retry with HELO
                    await SmtpStream.WriteLineAsync("HELO " + MtaIpAddress.Hostname);

                    response = await SmtpStream.ReadAllLinesAsync();

                    _LastActive = DateTime.UtcNow;
                    if (!response.StartsWith("250"))
                    {
                        failedCallback(response);
                        base.Close();
                    }
                }
                else
                {
                    // Server responded to EHLO
                    // Check to see if it supports 8BITMIME
                    if (response.IndexOf("8BITMIME", StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        _DataTransportMime = SmtpTransportMIME._8BitUTF;
                    }

                    // Check to see if the server supports pipelining
                    if (response.IndexOf("PIPELINING", StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        _CanPipeline = true;
                    }
                }
            }
            catch (IOException)
            {
                // Remote Endpoint Disconnected Mid HELO. Most likly Yahoo throttling.
            }


            _HasHelloed = true;
            _LastActive = DateTime.UtcNow;
            IsActive    = false;
            return(true);
        }
예제 #12
0
        /// <summary>
        /// Send the data to the server
        /// </summary>
        /// <param name="data">Data to send to the server</param>
        /// <param name="failedCallback">Action to call if fails to send.</param>
        public async Task <bool> ExecDataAsync(string data, Action <string> failedCallback, Func <string, Task> successCallbackAsync)
        {
            if (!base.Connected)
            {
                return(false);
            }

            _LastActive = DateTime.UtcNow;
            IsActive    = true;

            await SmtpStream.WriteLineAsync("DATA");

            string response = await SmtpStream.ReadAllLinesAsync();

            // If the remote MX supports pipelining then we need to check the MAIL FROM and RCPT to responses.
            if (_CanPipeline)
            {
                // Check MAIL FROM OK.
                if (!response.StartsWith("250"))
                {
                    failedCallback(response);
                    IsActive = false;
                    return(false);
                }


                // Check RCPT TO OK.
                response = await SmtpStream.ReadAllLinesAsync();

                if (!response.StartsWith("250"))
                {
                    failedCallback(response);
                    IsActive = false;
                    return(false);
                }

                // Get the Data Command response.
                response = await SmtpStream.ReadAllLinesAsync();
            }

            _LastActive = DateTime.UtcNow;

            if (!response.StartsWith("354"))
            {
                failedCallback(response);
                IsActive = false;
                return(false);
            }

            // Increment the data commands as server has responded positiely.
            _DataCommands++;

            // Send the message data using the correct transport MIME
            SmtpStream.SetSmtpTransportMIME(_DataTransportMime);
            await SmtpStream.WriteAsync(data, false);

            await SmtpStream.WriteAsync(MtaParameters.NewLine + "." + MtaParameters.NewLine, false);

            _LastActive = DateTime.UtcNow;

            // Data done so return to 7-Bit mode.
            SmtpStream.SetSmtpTransportMIME(SmtpTransportMIME._7BitASCII);


            response = await SmtpStream.ReadAllLinesAsync();

            _LastActive = DateTime.UtcNow;
            IsActive    = false;


            if (!response.StartsWith("250"))
            {
                failedCallback(response);
            }
            else
            {
                await successCallbackAsync(response);
            }


            // If max messages have been sent quit the connection.
            if (_DataCommands >= OutboundRuleManager.GetMaxMessagesPerConnection(MXRecord, MtaIpAddress))
            {
                ExecQuitAsync().Wait();
            }

            return(true);
        }