/// <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)); }
public async Task TestWriteAsync() { using (var stream = new SmtpStream(new DummyNetworkStream(), new NullProtocolLogger())) { var memory = (MemoryStream)stream.Stream; var buffer = new byte[8192]; var buf1k = new byte[1024]; var buf4k = new byte[4096]; var buf9k = new byte[9216]; byte [] mem; using (var rng = new RNGCryptoServiceProvider()) { rng.GetBytes(buf1k); rng.GetBytes(buf4k); rng.GetBytes(buf9k); } // Test #1: write less than 4K to make sure that SmtpStream buffers it await stream.WriteAsync(buf1k, 0, buf1k.Length); Assert.AreEqual(0, memory.Length, "#1"); // Test #2: make sure that flushing the SmtpStream flushes the entire buffer out to the network await stream.FlushAsync(); Assert.AreEqual(buf1k.Length, memory.Length, "#2"); mem = memory.GetBuffer(); for (int i = 0; i < buf1k.Length; i++) { Assert.AreEqual(buf1k[i], mem[i], "#2 byte[{0}]", i); } memory.SetLength(0); // Test #3: write exactly 4K to make sure it passes through w/o the need to flush await stream.WriteAsync(buf4k, 0, buf4k.Length); Assert.AreEqual(buf4k.Length, memory.Length, "#3"); mem = memory.GetBuffer(); for (int i = 0; i < buf4k.Length; i++) { Assert.AreEqual(buf4k[i], mem[i], "#3 byte[{0}]", i); } memory.SetLength(0); // Test #4: write 1k and then write 4k, make sure that only 4k passes thru (last 1k gets buffered) await stream.WriteAsync(buf1k, 0, buf1k.Length); await stream.WriteAsync(buf4k, 0, buf4k.Length); Assert.AreEqual(4096, memory.Length, "#4"); await stream.FlushAsync(); Assert.AreEqual(buf1k.Length + buf4k.Length, memory.Length, "#4"); Array.Copy(buf1k, 0, buffer, 0, buf1k.Length); Array.Copy(buf4k, 0, buffer, buf1k.Length, buf4k.Length); mem = memory.GetBuffer(); for (int i = 0; i < buf1k.Length + buf4k.Length; i++) { Assert.AreEqual(buffer[i], mem[i], "#4 byte[{0}]", i); } memory.SetLength(0); // Test #5: write 9k and make sure only the first 8k goes thru (last 1k gets buffered) await stream.WriteAsync(buf9k, 0, buf9k.Length); Assert.AreEqual(8192, memory.Length, "#5"); await stream.FlushAsync(); Assert.AreEqual(buf9k.Length, memory.Length, "#5"); mem = memory.GetBuffer(); for (int i = 0; i < buf9k.Length; i++) { Assert.AreEqual(buf9k[i], mem[i], "#5 byte[{0}]", i); } memory.SetLength(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); }