How to authenticate an incoming email transmission in SMTP server? - c#

I'm using the code from this project to write my own SMTP server.
So far I have this code (just a snippet from the project I linked to above):
TcpListener listener = new TcpListener(IPAddress.Any, nListeningPort);
listener.Start();
TcpClient client = listener.AcceptTcpClient();
client.ReceiveTimeout = 5000;
NetworkStream stream = client.GetStream();
//How do I authenticate incoming SMTP connection?
//In other words, how do I check user name and password?
//Begin reading stream
System.IO.StreamReader reader;
System.IO.StreamWriter writer;
reader = new System.IO.StreamReader(stream);
writer = new System.IO.StreamWriter(stream);
writer.NewLine = "\r\n";
writer.AutoFlush = true;
for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
{
Console.WriteLine("Read line {0}", line);
switch (line)
{
case "DATA":
writer.WriteLine("354 Start input, end data with <CRLF>.<CRLF>");
StringBuilder data = new StringBuilder();
//And so on...
writer.WriteLine("250 OK");
client.Close();
break;
//Other cases...
}
}
It works fine, but it accepts any SMTP connection.
My question is how do I authenticate it, or check for correct use name and password?
EDIT: I just realized that it is important to add the following. I need to code this SMTP server for our intranet to service outbound emails from one particular application (that I cannot control source code for.)
The application evidently uses Redemption.SafeMailItem object as the SMTP client to send out emails. Here's pseudo code that I got from disassembling it:
//Code below was extracted using dotPeek
Microsoft.Office.Interop.Outlook.Application application = Interaction.CreateObject("Outlook.Application", "");
SafeMailItem safeMailItem = Interaction.CreateObject("Redemption.SafeMailItem", "");
MailItem mailItem = application.CreateItem(OlItemType.olMailItem);
safeMailItem.Item = mailItem;
safeMailItem.Recipients.Add(strRecipient);
safeMailItem.Body = sBody;
safeMailItem.Attachments.Add((object) strPath, (object) Missing.Value, (object) Missing.Value, (object) Missing.Value);
NewLateBinding.LateSet((object) safeMailItem, (Type) null, "Subject", new object[1]
{
(object) sSubject
}, (string[]) null, (Type[]) null);
safeMailItem.Send();
application.GetNamespace("MAPI").SyncObjects[(object) 1].Start();

Related

POP3 protocol. Operations STAT and LIST

I try to realize simple mail client. Now I can retriev messages:
// create an instance of TcpClient
TcpClient tcpclient = new TcpClient();
// HOST NAME POP SERVER and gmail uses port number 995 for POP
tcpclient.Connect("pop.gmail.com", 995);
// This is Secure Stream // opened the connection between client and POP Server
System.Net.Security.SslStream sslstream = new SslStream(tcpclient.GetStream());
// authenticate as client
sslstream.AuthenticateAsClient("pop.gmail.com");
//bool flag = sslstream.IsAuthenticated; // check flag
// Asssigned the writer to stream
StreamWriter sw = new StreamWriter(sslstream);
// Assigned reader to stream
StreamReader reader = new StreamReader(sslstream);
// refer POP rfc command, there very few around 6-9 command
sw.WriteLine("USER my_mail#gmail.com");
// sent to server
sw.Flush();
sw.WriteLine("PASS my_pass");
sw.Flush();
// this will retrive your first email
sw.WriteLine("RETR 1");
sw.Flush();
string str = string.Empty;
string strTemp = string.Empty;
while ((strTemp = reader.ReadLine()) != null)
{
// find the . character in line
if (strTemp == ".")
{
break;
}
if (strTemp.IndexOf("-ERR") != -1)
{
break;
}
str += strTemp;
}
//str = reader.ReadToEnd();
// close the connection
sw.WriteLine("QUIT");
sw.Flush();
richTextBox2.Text = str;
But when I try to realize operations STAT and LIST my programm crashes. I think there is a problem in cycle of reading streams. For operation STAT I try to read until "\r\n" (strTemp = "\r\n") and for operation LIST - ".\r\n" respectively.
This is my code for STAT:
// create an instance of TcpClient
TcpClient tcpclient = new TcpClient();
// HOST NAME POP SERVER and gmail uses port number 995 for POP
tcpclient.Connect("pop.gmail.com", 995);
// This is Secure Stream // opened the connection between client and POP Server
System.Net.Security.SslStream sslstream = new SslStream(tcpclient.GetStream());
// authenticate as client
sslstream.AuthenticateAsClient("pop.gmail.com");
//bool flag = sslstream.IsAuthenticated; // check flag
// Asssigned the writer to stream
StreamWriter sw = new StreamWriter(sslstream);
// Assigned reader to stream
StreamReader reader = new StreamReader(sslstream);
// refer POP rfc command, there very few around 6-9 command
sw.WriteLine("USER my_mail#gmail.com");
// sent to server
sw.Flush();
sw.WriteLine("PASS my_pass");
sw.Flush();
// this will retrive your first email
sw.WriteLine("STAT");
sw.Flush();
string str = string.Empty;
string strTemp = string.Empty;
while ((strTemp = reader.ReadLine()) != null)
{
// find the . character in line
if (strTemp == "\r\n")
{
break;
}
if (strTemp.IndexOf("-ERR") != -1)
{
break;
}
str += strTemp;
}
//str = reader.ReadToEnd();
// close the connection
sw.WriteLine("QUIT");
sw.Flush();
richTextBox2.Text = str;
After I press the button my main window is not responding. Where is my mistake?
Thank you!
Your app is most likely hung on ReadLine(). Note that StreamReader.ReadLine() does not include the \r\n. So your check for \r\n will never hit, hence that break statement will never hit.
You may simply need to change it to if (strTemp == ""). If that doesn't do the trick, you'll have to step through in the debugger.
Also note that blocking calls like this are not a good idea in the UI thread. You really should offload this to a background worker.

Getting attachment size from smtp server

I have problem with getting attachment size from smtp server.
For example user wants to send mail from smtp.gmail.com, I need to know how big attachment can I attach.
So, I want to send EHLO command to smtp server, but I have problem with it.
private long GetSizeAttachament()
{
long Size = 0;
TcpClient smtpTest = new TcpClient();
try
{
smtpTest.Connect(conf.SmtpServer, 25);
if (smtpTest.Connected)
{
NetworkStream ns = smtpTest.GetStream();
StreamReader clientStreamReader = new StreamReader(ns);
StreamWriter clientStreamWriter = new StreamWriter(ns);
clientStreamReader.ReadLine();
clientStreamWriter.WriteLine("EHLO somehost");
while (true)
{
string line = clientStreamReader.ReadLine();
if(line.StartsWith("250"))
{
if (Regex.Match(line, "250-SIZE (.*?)$").Groups.Count > 1)
{
Size = long.Parse(Regex.Match(line, "250-SIZE (.*?)$").Groups[1].Value);
break;
}
}
}
}
}
catch
{
}
smtpTest.Close();
return Size;
}
conf.SmtpServer is smtp server name - for exmaple smtp.gmail.com.
This code is freezing at
string line = clientStreamReader.ReadLine();
Any ideas why?

How to read the body of the message in the mail retrieve from gmail by using pop3 in c #?

This is code:
protected void Button9_Click(object sender, EventArgs e)
{
try
{
// create an instance of TcpClient
TcpClient tcpclient = new TcpClient();
// HOST NAME POP SERVER and gmail uses port number 995 for POP
tcpclient.Connect("pop.gmail.com", 995);
// This is Secure Stream // opened the connection between client and POP Server
System.Net.Security.SslStream sslstream = new SslStream(tcpclient.GetStream());
// authenticate as client
sslstream.AuthenticateAsClient("pop.gmail.com");
//bool flag = sslstream.IsAuthenticated; // check flag
// Asssigned the writer to stream
System.IO.StreamWriter sw = new StreamWriter(sslstream);
// Assigned reader to stream
System.IO.StreamReader reader = new StreamReader(sslstream);
// refer POP rfc command, there very few around 6-9 command
sw.WriteLine("USER your_gmail_user_name#gmail.com");
// sent to server
sw.Flush(); sw.WriteLine("PASS your_gmail_password");
sw.Flush();
// RETR 1 will retrive your first email. it will read content of your first email
sw.WriteLine("RETR 1");
sw.Flush();
// close the connection
sw.WriteLine("Quit ");
sw.Flush(); string str = string.Empty;
string strTemp = string.Empty;
while ((strTemp = reader.ReadLine()) != null)
{
// find the . character in line
if (strTemp == ".")
{
break;
}
if (strTemp.IndexOf("-ERR") != -1)
{
break;
}
str += strTemp;
}
textbox1.text = str;
textbox1.text += "<BR>" + "Congratulation.. ....!!! You read your first gmail email ";
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
}
The message body is a bunch of what appears to be random characters. I know it's not just a bunch of random characters but some code that needs to be parsed and converted. How can I read content in "message body"?
I know i'm not directly replying to your answer but reading email is a really complex task and I think you can achieve this better and faster with an external library instead of implementing it by yourself.
There are many good implementation, i usually use OpenPop.NET which works fine and is opensource.
https://sourceforge.net/projects/hpop/
You can find many example on internet because it is really popular.
http://hpop.sourceforge.net/examples.php
you can get all mail easly:
using(Pop3Client client = new Pop3Client())
{
// Connect to the server
client.Connect("pop.gmail.com", 995, true);
// Authenticate ourselves towards the server
client.Authenticate("username#gmail.com", "password", AuthenticationMethod.UsernameAndPassword);
// Get the number of messages in the inbox
int messageCount = client.GetMessageCount();
// We want to download all messages
List<Message> allMessages = new List<Message>(messageCount);
// Messages are numbered in the interval: [1, messageCount]
// Ergo: message numbers are 1-based.
// Most servers give the latest message the highest number
for (int i = messageCount; i > 0; i--)
{
allMessages.Add(client.GetMessage(i));
}
}
you can get the full raw message
var mailbody = ASCIIEncoding.ASCII.GetString(message.RawMessage);
or if it is an utf8 encoded email:
var encodedStringAsBytes = System.Convert.FromBase64String(message.RawMessage);
var rawMessage =System.Text.Encoding.UTF8.GetString(encodedStringAsBytes);
Instead if you want only the mail body you have to dig into the mail structure:
http://hpop.sourceforge.net/documentation/OpenPop~OpenPop.Mime.MessagePart.html
I know it is not an easy task but as I stated above emails are complex objects.

Send IMAP commands to GMail using C#

I've been trying to access my GMail account to retrieve the unread emails from my email account. However, I only con perform login... Anything after that doesn't work.
First of all I connect to the server, then send the login command and finally the examine command. The thing is that the responses that are receive refers only to the connection and to the login. After that, it just stops waiting for someting to read from the StreamReader.
try
{
// create an instance of TcpClient
TcpClient tcpclient = new TcpClient();
// HOST NAME POP SERVER and gmail uses port number 995 for POP
//tcpclient.Connect("pop.gmail.com", 995);
tcpclient.Connect("imap.gmail.com", 993);
// This is Secure Stream // opened the connection between client and POP Server
SslStream sslstream = new SslStream(tcpclient.GetStream());
// authenticate as client
sslstream.AuthenticateAsClient("imap.gmail.com");
bool flag = sslstream.IsAuthenticated; // check flag
// Asssigned the writer to stream
System.IO.StreamWriter sw = new StreamWriter(sslstream);
// Assigned reader to stream
System.IO.StreamReader reader = new StreamReader(sslstream);
sw.WriteLine("tag LOGIN user#gmail.com pass");
sw.Flush();
sw.WriteLine("tag2 EXAMINE inbox");
sw.Flush();
sw.WriteLine("tag3 LOGOUT ");
sw.Flush();
string str = string.Empty;
string strTemp = string.Empty;
try
{
while ((strTemp = reader.ReadLine()) != null)
{
Console.WriteLine(strTemp);
// find the . character in line
if (strTemp == ".")
{
//reader.Close();
break;
}
if (strTemp.IndexOf("-ERR") != -1)
{
//reader.Close();
break;
}
str += strTemp;
}
}
catch (Exception ex)
{
string s = ex.Message;
}
//reader.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
I was looking for just this sort of "Hello World" example to get me started. With the help of dkarp's answers, here's my take on Miguel's example:
static void Main( string[] args ) {
try {
TcpClient tcpclient = new TcpClient();
tcpclient.Connect( "imap.gmail.com", 993 );
SslStream sslstream = new SslStream( tcpclient.GetStream() );
sslstream.AuthenticateAsClient( "imap.gmail.com" );
if ( sslstream.IsAuthenticated ) {
StreamWriter sw = new StreamWriter( sslstream );
StreamReader sr = new StreamReader( sslstream );
sw.WriteLine( "tag LOGIN user#gmail.com pass" );
sw.Flush();
ReadResponse( "tag", sr );
sw.WriteLine( "tag2 EXAMINE inbox" );
sw.Flush();
ReadResponse( "tag2", sr );
sw.WriteLine( "tag3 LOGOUT" );
sw.Flush();
ReadResponse( "tag3", sr );
}
}
catch ( Exception ex ) {
Console.WriteLine( ex.Message );
}
}
private static void ReadResponse( string tag, StreamReader sr ) {
string response;
while ( ( response = sr.ReadLine() ) != null ) {
Console.WriteLine( response );
if ( response.StartsWith( tag, StringComparison.Ordinal ) ) {
break;
}
}
}
You might look at using a canned IMAP/SSL library instead - there is one that is still active here.
This alternative is not free.
The basis for one of these has source code that might be helpful since you want to roll your own protocol handler.
Your problem is that you're expecting POP responses from an IMAP server. POP terminates fetched messages with . and responds to other commands with a line beginning with either +OK or -ERR. IMAP doesn't. You're consuming all the server responses and then hanging, waiting for something to match your POP-like response parser. If you examine the returned data, you should see the remainder of the server's responses to your (properly-formatted) requests.
There is a possibility that the server isn't sending back responses to your second and third commands. This could be because you're trying to pipeline three requests; that is, you're sending the requests without waiting for the responses. The server is obliged to allow pipelining while in the SELECTED state, but the protocol doesn't guarantee that you can pipeline commands from the NOT AUTHENTICATED state.

Reading a POP3 server with only TcpClient and StreamWriter/StreamReader

I'm trying to read mails from my live.com account, via the POP3 protocol.
I've found the the server is pop3.live.com and the port if 995.
I'm not planning on using a pre-made library, I'm using NetworkStream and StreamReader/StreamWriter for the job. I need to figure this out. So, any of the answers given here: Reading Email using Pop3 in C# are not usefull.
It's part of a larger program, but I made a small test to see if it works. Eitherway, i'm not getting anything. Here's the code I'm using, which I think should be correct.
EDIT: this code is old, please refer to the second block problem solved.
public Program() {
string temp = "";
using(TcpClient tc = new TcpClient(new IPEndPoint(IPAddress.Parse("127.0.0.1"),8000))) {
tc.Connect("pop3.live.com",995);
using(NetworkStream nws = tc.GetStream()) {
using(StreamReader sr = new StreamReader(nws)) {
using(StreamWriter sw = new StreamWriter(nws)) {
sw.WriteLine("USER " + user);
sw.Flush();
sw.WriteLine("PASS " + pass);
sw.Flush();
sw.WriteLine("LIST");
sw.Flush();
while(temp != ".") {
temp += sr.ReadLine();
}
}
}
}
}
Console.WriteLine(temp);
}
Visual Studio debugger constantly falls over tc.Connect("pop3.live.com",995); Which throws an "A socket operation was attempted to an unreachable network 65.55.172.253:995" error.
So, I'm sending from port 8000 on my machine to port 995, the hotmail pop3 port.
And I'm getting nothing, and I'm out of ideas.
Second block: Problem was apparently that I didn't write the quit command.
The Code:
public Program() {
string str = string.Empty;
string strTemp = string.Empty;
using(TcpClient tc = new TcpClient()) {
tc.Connect("pop3.live.com",995);
using(SslStream sl = new SslStream(tc.GetStream())) {
sl.AuthenticateAsClient("pop3.live.com");
using(StreamReader sr = new StreamReader(sl)) {
using(StreamWriter sw = new StreamWriter(sl)) {
sw.WriteLine("USER " + user);
sw.Flush();
sw.WriteLine("PASS " + pass);
sw.Flush();
sw.WriteLine("LIST");
sw.Flush();
sw.WriteLine("QUIT ");
sw.Flush();
while((strTemp = sr.ReadLine()) != null) {
if(strTemp == "." || strTemp.IndexOf("-ERR") != -1) {
break;
}
str += strTemp;
}
}
}
}
}
Console.WriteLine(str);
}
What happens if you view the Network Traffic using Wireshark? Is it sending anything at all?
Edit: I can't connect via telnet to pop3.live.com at that port either. Have you managed to successfully connect via a pop3 email client ever?

Categories

Resources