Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Articles
Search: 

Reading emails from VFP without additional components - Part II
Roberto C. Ianni, February 1, 2005
We will continue some of the points mentioned in the previous article, in order to be able to implement message reception. The points to be developed are: POP3 Authentication (both Flat and MD5 authentication methods) and EMail parsing.
Summary
We will continue some of the points mentioned in the previous article, in order to be able to implement message reception. The points to be developed are: POP3 Authentication (both Flat and MD5 authentication methods) and EMail parsing.
Description

This article is the beginning of eMail reception from VFP, complemented with the previous articles on eMail sending from VFP. In order to do this, we shall have to use the POP3 protocol (Post Office Protocol 3)

Objetives

We will continue some of the points mentioned in the previous article, in order to be able to implement message reception.

The points to be developed are:

  • POP3 Authentication
    • Flat authentication
    • MD5 authentication
  • eMail parsing

POP3 authentication

Authentication in POP3 servers is mandatory, different from SMTP which is optional, for which reason data from the user must be sent to the server, so it autenticates it and allows the examination of all messages stored in the inbox.

The POP3 protocol has several methods for authentication, of which we are going to examine two: flat authentication and MD5. To do this we shall have to use the commands from the previous article, USER/PASS and APOP.

Flat authentication

This type of authentication is very simple, as in the case of SMTP: the data are transferred in a flat manner to the server and the latter validates the data and responds whether they are or not valid.

USER ianni_roberto@server.com.ar
+OK password required for user ianni_roberto@server.com.ar
PASS 123456789
-ERR [AUTH] Authentication failed

As can be seen in this example, we first pass the user name to the server and it answers saying that it is waiting for the user password. Then, POP3 has to reply "+OK" or "-ERR". This gives us an indication whether the data sent to the server are valid or, in case "-ERR" is returned, almost always it is accompanied by a descriptive message with the reason the error occurred, in this case, an authentication error ( "[AUTH] Authentication failed" ).

As seen, this type of authentication is really very simple but also not very safe, because any person could catch the packages traveling through the network, and get very easily the user name and password.

MD5 authentication

This type of validation guards against someone listening in the network and catching the information package being sent, with user name and password, to the POP3 server. If this person could get the package, it would be of little use to him, because the information sent is not clear, and is only valid in the context of the connection already made, between the client (who sent the password) and the POP3 server (receiving the password). This means that the password sent changes every time a connection to the POP3 occurs.

In order to send the password in the MD5 format, the APOP command should be used. As already seen this command includes the USER and PASS commands, receiving the user name as the parameter, as well as the password, both in a flat manner.

APOP ianni_roberto@server.com.ar 65c28d9c3edff5d31b644225287885b2
+OK

As seen in the example, we first send the user name to the APOP command, which is the same we send it with the USER command. Then we send a separation space, and as a last parameter, we send the user password in MD5 format.

This MD5 formatted password is the one that changes with every connection made on the POP3 server. This is based on the way the password is generated in this format.

In order to correctly generate the password, the POP3 server sends us the following information, when we obtain the connection: a series of numbers and a time stamp, which it combines with our password using the MD5 algorithm. The result is a series of letters and numbers through which we cannot return to the original password.

Connection example:

telnet 127.0.0.1 110
Welcome to the POP3 server, version 1.1.0.1.9 beta <123654789>
APOP ianni_roberto@server.com.ar 65c28d9c3edff5d31b644225287885b2
+OK

In the example we can see how we connect to the POP3 server and, in establishing the conversation, the server sends a first line where it greets us and indicates the time stamp we need for the MD5 verification.

The time stamp is always surrounded by the greater and less than signs "<>" and in some cases, it can also have letters, in addition to the numbers. We then generate a password, joining the original password to the server time stamp. This is the password we send to the server. In order to verify this password, the server does the same thing: it generates a password with the timestamp sent plus the original password sent by the user. If the data are equal, the password is real.

Then we take the number sent by the server "123654789" and join it to the password "MiClave". When we apply the algorithm we get as a result the temporary password "65c28d9c3edff5d31b644225287885b2" which is the one being sent to the server.

I implemented the algorithm in C++, within the FLL FoxUtils library, with an exposed function called EncodeMD5. I did this in C++, not because of any limitation in VFP, but for comfort in writing the algorithm, because it has a lot of bit level management.

In the FoxUtils.prg class we shall implement a new method called StringEncodeMD5, which will be in charge of calling the FLL function, that result being the one we shall send to the POP3 as a temporary user password.

DEFINE CLASS WPop3 AS CUSTOM OLEPUBLIC
   ...
   *|-- MD5 authentication.-
   lsPassMD5 = This.m_ObjUtils.StringEncodeMD5( ALLTRIM( This.m_sTimeStamp ) ;
    + ALLTRIM( This.m_PassPOP3 ) )
   IF( This.m_SocketConn.Enviar( "APOP " + ALLTRIM( This.m_UsrPOP3 ) ;
    + " " + ALLTRIM( lsPassMD5 ) + ENTER ) )
      IF( !This.VerificarRespuesta( THIS.m_SocketConn.Recibir(), NO_ERRORS ) )
         This.m_Error = "User or password invalid"
         RETURN .F.
      ENDIF
   ENDIF
   ...
ENDDEFINE

DEFINE CLASS FoxUtils AS Custom
   ...
   PROCEDURE StringEncodeMD5( lsToEncode )
      RETURN( EncodeMD5( lsToEncode ) )
   ENDPROC
   ...
ENDDEFINE

MD5 algorithm

With what we have seen thus far, we can say, without many details, that the MD5 (Message-Digest Algorithm) is a hash function, also called "one-way" because given a text (a bytes sequence) a unique value is returned, but starting with that unique value the original text. Hence the name "one way or one address". For those of you who know CRC, you will realize that it is the same thing, but with another algorithm.

In order to implement it within the FLL, we have something like this:

FoxInfo myFoxInfo[] =
{
   {"EncodeMD5", (FPFI) EncodeMD5, 1, "C"},
};

I do not want to go into too much detail, because it would be too long and the sense of this article would be lost. The point here is to explain how to receive POP3 messages, but I give you the implementation in the FLL so you can see it, and the theory behind it all at http://www.faqs.org/rfcs/rfc1321.html.

eMail parsing

As seen in the previous article, when we ask the POP3 server to give us a message, it returns a string containing the whole email, so in order to obtain the detail information on who sends the message, at what time, to whom reply, how many attachments have to be parsed in the string, etc., we use this code:

RETR 1
+OK
Return-Path: 
Delivered-To: CI-ianni_roberto@server.com.ar
Received: (qmail 2516 invoked from network); 31 Aug 2004 10:55:57 -0000
Received: from unknown (HELO postino9.prima.com.ar) (172.16.1.100)
  by cumeil13.int.prima.com.ar with SMTP; 31 Aug 2004 10:55:57 -0000
Received: (qmail 63214 invoked by uid 10006); 31 Aug 2004 10:55:57 -0000
Received: (Antivirus 0e1d36106fc2798aa1704741707bfb9c); 31 Aug 2004 10:55:57 -0000
Received: (qmail 63186 invoked from network); 31 Aug 2004 10:55:56 -0000
Received: from unknown (HELO hotmail.com) (64.4.47.34)
  by postino9.prima.com.ar with SMTP; 31 Aug 2004 10:55:56 -0000
Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC;
    Tue, 31 Aug 2004 03:55:54 -0700
Received: from 201.254.49.143 by by9fd.bay9.hotmail.msn.com with HTTP;
   Tue, 31 Aug 2004 10:55:54 GMT
X-Originating-IP: [201.254.49.143]
X-Originating-Email: [ianni_roberto@hotmail.com]
X-Sender: ianni_roberto@hotmail.com
From: "Roberto Ianni" 
To: ianni_roberto@server.com.ar
Bcc:
Subject: Test POP3
Date: Tue, 31 Aug 2004 07:55:54 -0300
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="----=_NextPart_000_4c56_2fea_2f76"
Message-ID: 
X-OriginalArrivalTime: 31 Aug 2004 10:55:54.0449 (UTC) FILETIME=[16679C10:01C48F49]

This is a multi-part message in MIME format.

This simple example on how the server returns a message, through the RETR command, allows us to see that each line is separated by an ENTER and that each one has an identifier and a value: "To: ianni_roberto@server.com.ar". In this case "To" is the identifier and "ianni_roberto@server.com.ar" is the value.

Suppose we want to obtain the subject from the message. We would have to examine line by line until we found the "Subject:" identifier and the value of this identifier would be the subject that the person originating the email placed there. Here is a simple implementation:

PROTECTED ObtenerLineHeader( lsFindLine, lsLine )
   lnPos = ATCLINE( lsFindLine, This.m_MailHeader )
   IF( lnPos > 0 )
      lsLine = MLINE( This.m_MailHeader, lnPos )
   ELSE
      lsLine = ""
      RETURN .F.
   ENDIF
ENDPROC

As we can see, the ObtenerLineHeader method is not complex at all.The only thing it does is use ATCLINE on the property containing the string returned by the POP3 server and, if found, it returns the whole line, with the identifier and the value. We would only have to obtain the line value.

So now we would have to get the subject, the only thing we want to know.

   sVal = SPACE(20)
   oMail.ObtenerLineHeader( "Subject:", @sVal )

We would have to repeat this procedure to obtain all the values from the message, such as the date, the message-ID , the x-sender, etc.

Conclusion

As seen, the points analyzed here are not complex at all and allowed us to understand two POP3 authentication mechanisms. We also understood how to obtain the values we wanted from the string formed by the message. With these foundations we are ready to get the BodyParts of the message, either the message body or the attached files.

Roberto C. Ianni, Banco Hipotecario
Roberto Ianni (Buenos Aires, Argentina) is a professional software developer for the last 4 years. He has programmed in C++, VFP, VC++, C#, and has lots of experience in VFP and VC++. He currently works in the Banco Hipotecario as an Analyst-Developer.
More articles from this author
Roberto C. Ianni, December 1, 2004
Today we are going to talk about data compression. This is something we do frequently, something which is useful for many different tasks.
Roberto C. Ianni, June 1, 2004
The "EventLog" or "Event viewer" is something we use on a daily basis, to obtain information about what happened to our computer at a certain moment; for example, when an application generates an error, most of us will intuitively look at the EventLog to see what information it left for us.
Roberto C. Ianni, May 1, 2004
The "EventLog" or "Event viewer" is something we use every day, to obtain information about what happened to our computer at a certain moment. For example, when an application generates an error, most of us instinctively go to the EventLog to see what information it left for us.
Roberto C. Ianni, July 1, 2004
One of the great limitations I find in VFP is the lack of low-level manipulation I can obtain from it. For many, this might not be an inconvenience, but several times I have encountered a problem which can't be solved with Fox, and it is then that I use a DLL or an FLL.
Roberto C. Ianni, August 1, 2004
As an objective for this issue, I want to propose the following points, to complete the first part of the development of an FLL. Advanced development with an FLL; Accessing VFP data; Executing VFP commands from a FLL; MultiThreading; FLL with VFP 9.0; Executing Assembler from VFP.
Roberto C. Ianni, October 1, 2004
This article is the continuation of "Sending email through Visual FoxPro without additional components", published last March. Back when I wrote this article, I didn't think it would get such a huge response, but it did, hence, due to the mails coming from everywhere I decided to write again on that...
Roberto C. Ianni, November 1, 2004
In this second part we will learn how to: Implement MIME, Attach binary files, the final implementation of the WSendMail class, and the use of the WSendMail class.
Roberto C. Ianni, May 1, 2005
Windows Control Panel holds the configuration from several of the operating system's applications, and from some other applications that provide an applet to appear there. Learn how to build this kind of applets to give your application a professional configuration mechanism.
Roberto C. Ianni, April 1, 2005
The intention of this article is to finish with the use of POP3 (Post Office Protocol 3), implementing everything we have seen so far.
Roberto C. Ianni, January 1, 2005
This article is the beginning of receiving email from VFP; this is complemented with the articles you have already seen about sending email from VFP. To be able to do this, we will have to use the POP3 protocol (Post Office Protocol 3).
Roberto C. Ianni, March 1, 2004
Many of us send email using third-party tools such as Outlook Express or Microsoft Outlook, among others, and most likely have encountered registration problems in the client, licencing problems, OLE errors that only occurr at the client's site but not in our developer environment. Also problems if ...
Roberto C. Ianni, August 1, 2006
The present article is one of those that Martín Salías calls "low level fox", the general idea is to develop a service for the operative system whose only goal will be to run a VFP application in charge of handling the business logic.