How to get attachment(s) from mail?

General Help regarding HMG, Compilation, Linking, Samples

Moderator: Rathinagiri

User avatar
Alex Gustow
Posts: 290
Joined: Thu Dec 04, 2008 1:05 pm
Location: Yekaterinburg, Russia
Contact:

How to get attachment(s) from mail?

Post by Alex Gustow »

I need to create program for little automizing of our office work (chief want it at Monday - so I must do it quickly).

Process description:
Our clients (hospitals - about 150-200) will send to us (to known e-mail address) their reports (4 .XLS files attached to one mail message) EACH DAY.
We must get their mails, "save to" their attachments (to pre-defined folder)... and other program must create a summary report from their XLSs... ("other program" - is not my task, other programmer writes it).

My program (it runs by Win Sheduler every hour) must do that:
1) connect to mail-server;
2) logon (post login and password);
3) get mail's quantity (BTW how I can get number of NEW mails? or how I can separate NEW mail message from OLD one?);
4) read each mail message;
5) ask "you have attachements?" :)
6) if "yes" - get array with attachtment's filenames;
7) save (if exists) all XLSs to folder
8) goto point (4)
9) close connection.

I never tried to work with mails from HMG before. I looked to SAMPLES, looking for "*mail*.*" files. I found "\Advanced\DeleteEmail" and "\Applications\MultipleMail" samples - it helps me on start line...

Little sample (what I can do right now):

Code: Select all

  public cServer, cUser, cPass, aMessages, nMsgs, i, j

  cServer := "82.122.253.164"
  cUser   := "gripp"
  cPass   := "1234554321"

  oSocket := TPop3():New()

  // try to connect to mail server

  if oSocket:Connect( alltrim(cServer) )

    MsgInfo( "Yes, connection to [ " + cServer + " ] exists !!!" )

    // try to login

    if oSocket:Login( alltrim(cUser), alltrim(cPass) )

      MsgInfo( "Yes, login as [ " + cUser + " ] exists !!!" )

      // do we have mails into InBox?
      aMessages := oSocket:List(.T.)         // .F.

      // .F. - array with subarrays: {cMsgID, val(cSize)}
      //                               (ID and message size)
      // .T. - array with subarrays: { cMsgID, val(cSize), cSubject }
      //                               (ID, message size, subject)

      nMsgs := Len(aMessages)

      if nMsgs > 0

        txt :=  "Yes, we have mails!!! Quantity = " + ;
                 ltrim(str( nMsgs )) + CRLF + CRLF + "ID  size  subject"

        for i:=1 to nMsgs
          txt := txt + CRLF
          txt := txt + aMessages[i,1]
          txt := txt + "   " + str(aMessages[i,2], 8)
          txt := txt + iif( len(aMessages[i])=3, ;
                            "  subject: " + trim(aMessages[i,3]), ;
                            "" )
        next i

        MsgInfo( txt )

        // get message text and show it
        for i:=1 to nMsgs

          txt := "Message № " + ltrim(str(i)) + CRLF + CRLF + "Message text:" + CRLF
          txt := oSocket:GetMessageText( aMessages[i,1] )

          MsgInfo( txt )

        next i

///// 1) how to know: is it NEW message?
///// 2) how to know: this message has attachments?
///// 3) how to get attachments list (with filenames)?
///// 3) how "save to" attachments?

      else

        MsgInfo( "Oops... InBox is empty." )

      endif

    else

      MsgStop( "Oops... I couldn't login (???)" )

    endif

  else

    MsgStop( "Oops... I couldn't connect to mail-server [ " + cServer + " ] (???)" )

  endif

  oSocket:Close()    // after work close connection (DO IT !)
Maybe someone can help me how to solve my troubles?

User avatar
Roberto Lopez
HMG Founder
Posts: 3987
Joined: Wed Jul 30, 2008 6:43 pm
Has thanked: 27 times
Been thanked: 173 times

Post by Roberto Lopez »

Alex Gustow wrote:I need to create program for little automizing of our office work (chief want it at Monday - so I must do it quickly).
<...>
As far as I know, Matteo Baccan socket library does not have such functonality. This is TPOP3 class:

Code: Select all

CLASS TPOP3
   METHOD New()
   METHOD Connect( cAddress, nPort )
   METHOD Close()
   METHOD Login( cUser, cPwd )
   METHOD List( lFullInfo )
   METHOD GetMessageHeader( cMessageID )
   METHOD GetMessageText( cMessageID )
   METHOD DeleteMessage( cMessageID )
   VAR oSocket HIDDEN
ENDCLASS
But HBTIP could be helpful on that. I've attached to this message the full source code and samples from Harbour SVN.

I hope that be helpful.
Attachments
hbtip.rar
(100.45 KiB) Downloaded 374 times
Regards/Saludos,

Roberto


(Veritas Filia Temporis)

User avatar
Alex Gustow
Posts: 290
Joined: Thu Dec 04, 2008 1:05 pm
Location: Yekaterinburg, Russia
Contact:

Post by Alex Gustow »

Thanks Roberto!
I'll try to learn it (never seen before - interesting thing for 1st view!).
Maybe I'll try to use MAPI (Simple MAPI or MAPI 1.0) functions - but it takes time to understanding.
In any case - I'll have expirience with this problem (and post results here of course).

User avatar
Alex Gustow
Posts: 290
Joined: Thu Dec 04, 2008 1:05 pm
Location: Yekaterinburg, Russia
Contact:

Post by Alex Gustow »

I rewrite my program (now I use classes from TIP.LIB [it comes with HMG Ext, look at folder "MiniGUI\Harbour\Lib"] - Roberto posted it as sources of HBTIP library in this thread). And what I can (and can't) for today:

Simple sample (into "Inbox" I have 3 mails - 2 "new" and 1 "old"):

Code: Select all

It compiles as: 
  
 call c:\MiniGUI\Batch\Compile.bat GrippMail /l tip 
  
 --------- start of code -------- 
  
 local oMail, cUrl, oUrl, oClient, txt 

 // it's not REALLY address - for example only 
 cUrl := "pop://gripptest:gripptest@26.188.255.166" 
  
 if empty( alltrim( cUrl ) ) 
   MsgInfo( "Invalid (empty) URL: " + cUrl ) 
   Return Nil 
 endif 
  
 oUrl := tURL():New( cUrl ) 
  
 if empty( oUrl ) 
   MsgInfo("oUrl -- Invalid URL : [ " + cUrl + " ]") 
   Return Nil 
 else 
   MsgInfo("oUrl created!") 
 endif 
  
 oClient := TIpClientPop():new( oUrl ) 
  
 if empty( oClient ) 
   MsgInfo("oClient -- Invalid URL : [ " + cUrl + " ]") 
   Return Nil 
 else 
   MsgInfo("oClient created!") 
 endif 
  
 oClient:nConnTimeout := 2000    //:= 20000 
 oUrl:cUserid := strtran( oUrl:cUserid, "&at;", "@" )  
  
 if oClient:Open() 
  
   if empty( oClient:cReply ) 
     MsgInfo( "Connecting to " + oUrl:cProto + "://" + oUrl:cServer + CRLF + ; 
                 "Connection status: <connected>" ) 
   else 
     MsgInfo( "Connecting to " + oUrl:cProto + "://" + oUrl:cServer + CRLF + ; 
                "Connection status: " + oClient:cReply ) 
   endif 

   // it returns .T.
   txt := "oClient:isOpen = " + iif( oClient:isOpen, ".T.", ".F." ) 
   MsgInfo( txt ) 
  
   // in my case it returns -1 and 0 
   txt := "oClient:nLength = " + ltrim(str( oClient:nLength )) + CRLF + ; 
          "oClient:nRead = " + ltrim(str( oClient:nRead )) 
   MsgInfo( txt ) 
  
   // in my case returns string:
   // "+ОК " + (amoun of mails) + (amount of bytes)(ie summary size) 
   txt := "oClient:Stat() = " + oClient:Stat() 
   MsgInfo( txt ) 
  
   // it returns string (divided by CRLF): 
   // into substrings: ("mail number" "mail size") (for example: "1 32452" + CRLF ) 
   txt := "oClient:List() = " + CRLF + oClient:List() 
   MsgInfo( txt ) 
  
   // it returns value greater on 1 (not 3 but 4)
   txt := "Amount of mails into Inbox ( oClient:countMail ): " + ; 
          ltrim(str( oClient:countMail ))
   MsgInfo( txt ) 
  
   // attempt to get "unique ID" (if without parameter - _all_ mails) 
   // returns string (divided by CRLF - if _all_ mails) 
   // (into substring -  
   //   "1 MD50000000001:MSG:18386:30041174:1176554496" ) 
   txt := "oClient:UIDL( ) = " + CRLF + oClient:UIDL( ) 
   MsgInfo( txt ) 
   // for _one_ it returns only UIDL ( "MD5..." ) 
   txt := "oClient:UIDL( 1 ) = " + CRLF + oClient:UIDL( 1 ) 
   MsgInfo( txt ) 
  
   // METHOD Read( nLen ) CLASS tIPClientPOP 
   // ... 
   // RETURN ::Retrieve( Val( ::oUrl:cFile ), nLen ) 
  
   txt := 'valtype( oClient:Read( 1 ) ) = "' + valtype( oClient:Read( 1 ) ) + '"' 
   MsgInfo( txt ) 
  
   // attempt to get 1st mail 
   txt := "oClient:Read( oClient:UIDL( 1 ) ) = " + CRLF + ; 
          "--- start --" + CRLF + ; 
          oClient:Read( oClient:UIDL( 1 ) ) + CRLF + ; 
          "--- finish ---" 
   MsgInfo( txt ) 
   // ? it return that most, as List() returns
   // ? how to get mail, if I know it's number into Inbox (or UIDL) ?? 
  
   /* 
   // try to get mail with Retrieve (2nd mail, 100 bytes) 
   txt := "oClient:Retrieve( 2, 100 ) = " + CRLF + ; 
          "--- start --" + CRLF + ; 
          oClient:Retrieve( 2, 100 ) + CRLF + ; 
          "--- finish ---" 
   MsgInfo( txt ) 
   // "Kaspersky Mail-Checker" runs - 
   //   I.e. the letter is validly obtained 
   // but... result is empty string (??) maybe it is object?..
   */ 
  
   /* 
   // try to get mail with Retrieve (2nd mail, all mail - from begin to end) 
   txt := "oClient:Retrieve( 2 ) = " + CRLF + ; 
          "--- start --" + CRLF + ; 
          oClient:Retrieve( 2 ) + CRLF + ; 
          "--- finish ---" 
   MsgInfo( txt )
   // "Kaspersky Mail-Checker" runs - 
   //   I.e. the letter is validly obtained 
   // but... result is empty string (??) maybe it is object?..
   */ 
  
   // check type - what Retrieve() returns  
   txt := 'valtype( oClient:Retrieve( 2 ) ) = "' + ; 
          valtype( oClient:Retrieve( 2 ) ) + '"' 
   MsgInfo( txt ) 
   // тип - "С" 
      
   // ... to be continued (I want to eat and it is time in bed)

   // ... to do: how I can get 1st "new" (or "old") mail?
  
   // close session (it's necessary!) 
  
   oClient:Quit()    // look at HBTIP\POPCLI.PRG 
  
   oClient:Close() 
  
   MsgInfo( "Session closed." + CRLF + "Done: " + ; 
            iif( empty( oClient:cReply ), ; 
                 "(no goodbye message)", ; 
                 'goodbye message "' + oClient:cReply + '"' ) ) 
  
 else 
  
   if empty( oClient:cReply ) 
     MsgInfo( "Can't open URI " + cUrl ) 
   else 
     MsgInfo( "Can't open URI " + cUrl + CRLF + ; 
              'oClient:Reply = "' + oClient:cReply + '"') 
   endif 
  
 endif 
  
 MsgInfo( "That's all folks!" ) 
  
 oMail := .F. 
 cUrl := .F. 
 oUrl := .F. 
 oClient := .F. 
  
 ---------- finish of code -------------
It's my start step. But I don't know yet how I can:
- to get list of NEW mails (or check - is this 2nd mail "new"?);
- get (for example) 1st mail;
- check "do you have attach(es)";
- if "yes" - save attach(es) to pre-define folder;
- marked mail as "read";

Advices?

P.S. This work should be made urgently - the reports from hospitals about the patients by an influenza will be treated (and now in Russia there is epidemic - as well as all over the world, as is known)

P.P.S. My "expirience" in this part of Harbour programming may be useful for many HMG-heads (I think). "Enlarge your... HMG-power!" :)

ClaudioGalera
Posts: 47
Joined: Tue Jul 14, 2009 1:14 pm
Location: Mar del Plata, Argentina

Post by ClaudioGalera »

Hi, Alex

You can play with the POP protocol with TELNET
Please read this, here's how to connect and how to use
http://www.yuki-onna.co.uk/email/pop.html
and http://en.wikipedia.org/wiki/Post_Office_Protocol - Google : http://www.google.com.ar/#hl=es&q=telne ... 43995f18ee
My program (it runs by Win Sheduler every hour) must do that:
1) connect to mail-server;
2) logon (post login and password);
3) get mail's quantity (BTW how I can get number of NEW mails? or how I can separate NEW mail message from OLD one?);
4) read each mail message;
5) ask "you have attachements?" :)
6) if "yes" - get array with attachtment's filenames;
7) save (if exists) all XLSs to folder
8) goto point (4)
9) close connection.


1) I do not know as the use of the library, but you must specify the POP server name with port 110
2) send to the server the command

Code: Select all

USER userName
send the password

Code: Select all

PASS passW0rd
3) for the amount we list the mail that has the server via the command
LIST

and returns a message similar

Code: Select all

+OK 3 messages
1 1205
2 305
3 344400
The first number is the Id mail and next number the size in bytes.
How to distinguish the new from the old mail? Simple, after you lose the mail to the client pc and once given the ok, you are given the order to delete on the server. The next time that you go to see, you will see only the new.
4) whit the command

Code: Select all

RETR msg#

where msg# is the id number of the LIST
5-6-7) the attachements is encoded in the mails body as MIME data.
You will have to analyze the mail's body and view the contents. Then decoded the MIME part.
Next save the data, and if all ok delete the mail on the server

Code: Select all

DELE msg#
8)...
9) Use

Code: Select all

QUIT
"This deletes any messages marked for deletion, and then logs you off of the mail server. This is the last command to use. This does not disconnect you from the ISP, just the mailbox." http://techhelp.santovec.us/pop3telnet.htm

I hope that you find this helpful. I have never used at Harbor-HMG, only on VBasic investigating pop protocol.
Sorry for my english. Regards
Claudio

User avatar
Alex Gustow
Posts: 290
Joined: Thu Dec 04, 2008 1:05 pm
Location: Yekaterinburg, Russia
Contact:

Post by Alex Gustow »

Hi Claudio!

Many thanks for advices - very-very interesting!

I'll play with it tomorrow (right now it's 20:30 - but I still sit in office and try to write something... oh my poor head! :( no, stop! enough! I'm coming home :) )

If I'll do some useful - I'll post about it on forum of course.

User avatar
Alex Gustow
Posts: 290
Joined: Thu Dec 04, 2008 1:05 pm
Location: Yekaterinburg, Russia
Contact:

Post by Alex Gustow »

PROBLEM SOLVED !

Thanks to all, brothers, for support and help! :)

See little description here:
http://hmgforum.com/viewtopic.php?p=6751#p6751

I'll post working sample (maybe it will helps to someone) ASAP.

User avatar
fchirico
Posts: 324
Joined: Sat Aug 23, 2008 11:27 pm
Location: Argentina

Post by fchirico »

Alex Gustow wrote:PROBLEM SOLVED !

I'll post working sample (maybe it will helps to someone) ASAP.
Alex,

I am interested in the topic, when you can, please post an example.

Thanks in advance.
Saludos, Fernando Chirico.

User avatar
Alex Gustow
Posts: 290
Joined: Thu Dec 04, 2008 1:05 pm
Location: Yekaterinburg, Russia
Contact:

Post by Alex Gustow »

fchirico wrote:
Alex Gustow wrote:PROBLEM SOLVED !

I'll post working sample (maybe it will helps to someone) ASAP.
Alex,

I am interested in the topic, when you can, please post an example.

Thanks in advance.
OK - I'll try to post short but really working example tomorrow. It will increase our common knowledge and power of HMG (I hope)!

If you, guys, want - I'll upload here Help (.CHM) from xHarbour bundle (I downloaded it - bundle - from free.xharbour.com as I wrote yesterday). It contains (except for other) good description of classes and methods from TIP.LIB (TipClient, TipClientPOP, TipMail etc.) (with short but good examples). It was very useful (for me - in this difficult & unusual work). I think it will be useful for others (even for guys who does not use xHarbour - but Harbour only). If I only knew about it week back!..

I think I'll be not a "very bad boy" or "pirate" :) (Copyright 2006-2007 xHarbour.com - xHarbour Language Reference Guide version 1.1).

User avatar
fchirico
Posts: 324
Joined: Sat Aug 23, 2008 11:27 pm
Location: Argentina

Post by fchirico »

Alex Gustow wrote:
fchirico wrote:
Alex Gustow wrote:PROBLEM SOLVED !

I'll post working sample (maybe it will helps to someone) ASAP.
Alex,

I am interested in the topic, when you can, please post an example.

Thanks in advance.
OK - I'll try to post short but really working example tomorrow. It will increase our common knowledge and power of HMG (I hope)!
Ok, slowly, no problem.
If you, guys, want - I'll upload here Help (.CHM) from xHarbour bundle .....
Yes, please!
Here in Argentina we have a saying "The abundant, no harm."
I think I'll be not a "very bad boy" or "pirate" :) (Copyright 2006-2007 xHarbour.com - xHarbour Language Reference Guide version 1.1).
No, you are not a bad boy :evil:
Saludos, Fernando Chirico.

Post Reply