READING mail from /var/mail/user

Hello guys,

I'm in desperate need. I need to write a script that behaves like a "mail" shell program.

I've a base of the program -menu and so on, but what I cannot do is how to read messages from /var/mail/user. I would like to separate them as "mail" program does, but I;m just a newbie and cannot make it. I've tried it with grep -> so i get the line position of the mail header and then splitting up the messages, but I run to problems with saving lines and so on.

I will appreciate any help guys.
Thanks,
Peto

Any ideas how to get just one message from /var/mail/user?

Lemme ask you a question.

What do you think separates one message from the other?

Well, as far I know it is separated by Headers
From 'name' 'date' ...
TEXT

From ...

But, there is some TEXT just behind the header that isn't printed out by 'mail', cuz its info about the delivery. But though I know this, I cannot make it. I tried to get positions of headers with grep, but I couldn't get it to the end.

ok, that's good.
What's the CONSISTENT first line of EVERY mail message?

Pls post a couple of samples here.

THIS IS ONE MESSAGE(TEXT in RED is written by MAIL program as Message content - I'd like the same):

From newbie@gmail.com Thu May 18 10:17:58 2006
Return-Path: <newbie@gmail.com>
Received: from relay.cv.cm (relay.cv.cm[147.32.80.7])
	by cv.cm (8.12.10+Sun/8.12.10) with ESMTP id k4I8Hw9W010121
	for <newbie@cv.cm>; Thu, 18 May 2006 10:17:58 +0200 (MEST)
Received: from py-out-1112.google.com (py-out-1112.google.com [64.233.166.181])
	by relay.cv.cm (8.13.4/8.13.4) with ESMTP id k4I8Hanf067227
	for <cv.cm>; Thu, 18 May 2006 10:17:55 +0200 (CEST)
	(envelope-from newbie@gmail.com)
Received: by py-out-1112.google.com with SMTP id t32so538943pyc
        for <newbie@cv.cm>; Thu, 18 May 2006 01:17:55 -0700 (PDT)
DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws;
        s=beta; d=gmail.com;
        h=received:message-id:date:from:to:subject:mime-version:content-type;
        b=nX4ViyhbdhgEfk92jDdHtfB1+4gGMImzF5znA9m/g3tJsqhAzg9LPI/b3NllfQB51SpfbP8NyG9oh8W7LSB8d9xBINz2rdPPX4HIAGBqSYvbOKod4eNU=
Received: by 10.35.40.10 with SMTP id s10mr241034pyj;
        Thu, 18 May 2006 01:17:55 -0700 (PDT)
Received: by 10.35.9.4 with HTTP; Thu, 18 May 2006 01:17:55 -0700 (PDT)
Message-ID: <7a04f4e906051098098516abbab9@mail.gmail.com>
Date: Thu, 18 May 2006 01:17:55 -0700
From: "ppppp" <newbie@gmail.com>
To: newbie@cv.cm
Subject: Noooo
MIME-Version: 1.0
Content-Type: multipart/alternative; 
	boundary="----=_Part_107903_11845770.1147940275262"
X-FELK-MailScanner-Information: Please contact the ISP for more information
X-FELK-MailScanner: Found to be clean
X-FELK-MailScanner-SpamCheck: not spam, SpamAssassin (score=-0.388,
	required 5, BAYES_00 -2.60, HTML_MESSAGE 0.00,
	HTML_SHORT_LENGTH 1.57, SARE_MSGID_LONG40 0.64, SPF_PASS -0.00)
X-FELK-MailScanner-From: newbie@gmail.com

Content-Length: 495

------=_Part_107903_11845770.1147940275262
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Nemam co napssaaat.


sssss

------=_Part_107903_11845770.1147940275262
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

<div>Nemam co napssaaat.</div>
<div>�</div>
<div>�</div>
<div>sssss</div>

------=_Part_107903_11845770.1147940275262--

how about something like this for starters:

nawk -f peto.awk path2VarMailUser

peto.awk:

BEGIN {
  # make 'records' to be separated by blank/empty lines
  RS=FS=""

  # create a pattern where something starts either one of listed strings
  headers="(^From )|(^Message-ID:)|(^Date:)|(^From:)|(^To:)|(^Subject:)"
}

# If a record starts with 'From ' ...
/^From / {

   # print the record number
   printf("\n\n=== THIS is MAIL MESSAGE #%d ===\n\n", ++msg)

   # iterate through the fields of a given 'record' - every field is a LINE, 
   # because records are 'blank line' separated sequesnce of lines
   for(i=1; i<=NF; i++) {

     # if a record field (a line) matches a pattern 'headers' - print that field
     if ( $i ~ headers) print $i
   }
}

# print any OTHER 'record' - this is a shorthand for 'print $0'
1

Yup..it helps..:)...though I'm not sure how it works.
So

headers="(^From )|(^Message-ID:)|(^Date:)|(^From:)|(^To:)|(^Subject:)"
headers can start with (From,Message-ID,Date...)

/^From/
and then if sentence start with "From" it does the for cyclus

printf("\n\n=== THIS is MAIL MESSAGE #%d ===\n\n", ++msg)
for(i=1; i<=NF; i++) {
if ( $i ~ headers) print $i
}
if the sentence is header then pprint? what does ( ( $i ~ headers)) this mean????

Also I would like to be able to write message text. The best would be if I could choose with Message number as you NAMED with evert message with last code.

THX a lot.
Peto

ok, I've updated the code with comments - should be clearER now. If it's not - do 'man nawk'.

I don't understand what you're asking, but if you understand the code and/or give a sample desired output I believe you can format the output any way you want.

Good luck

I got it, but wasnt sure. Now I understand it thx.

Is it possible to read from STDIN in NAWK? I cannot find it on internet. I would like to write max. 3 Mail Headers and then wait for user to press ENTER and then show next 3 headers and so on.

Well, I'm sorry if I didn't make my question clear. I don't really have any ideas how to write text written by sender in the /var/mail/user. I mean not just Header of the mail, but also mail and omit Msg Info for Server between Header and Message.

BEGIN {
  # make 'records' to be separated by blank/empty lines
  RS=FS=""

  # create a pattern where something starts either one of listed strings
  headers="(^From )|(^Message-ID:)|(^Date:)|(^From:)|(^To:)|(^Subject:)"
}

# If a record starts with 'From ' ...
/^From / {

   if ( !(++msg % 4) ) {
      printf "Please press ENTER: "
      getline myInput < "-"
   }

   # print the record number
   printf("\n\n=== THIS is MAIL MESSAGE #%d ===\n\n", msg)

   # iterate through the fields of a given 'record' - every field is a LINE, 
   # because records are 'blank line' separated sequesnce of lines
   for(i=1; i<=NF; i++) {

     # if a record field (a line) matches a pattern 'headers' - print that field
     if ( $i ~ headers) print $i
   }
}

# print any OTHER 'record' - this is a shorthand for 'print $0'
1

I don't understand what you're saying.......

Ok.I'll try to start expressing myself a bit better :).

Firstly, I considered last character '1' in peto.awk to be a typo so I didn't include it. But now as you've comment it, I see I was wrong. So I was asking exactly what you already did - sorry.

However, I'd like to ask one more question. Now, user can view 4 e-mails at once and then he is asked to press ENTER. However you have to press: CTRL+D and ENTER, ENTER(once more)
so it continues with printing out next mails. Is it possible to avoid this?

You helped me a lot and it's much clearer to me now.

Peto

hmm....... it seems not ALL the awk's support this paradigm - Solaris's 'nawk' seems to be one of them.

Try this:

BEGIN {
  # make 'records' to be separated by blank/empty lines
  RS=FS=""

  # create a pattern where something starts either one of listed strings
  headers="(^From )|(^Message-ID:)|(^Date:)|(^From:)|(^To:)|(^Subject:)"
}

# If a record starts with 'From ' ...
/^From / {

   if ( !(++msg % 4) ) {
      printf "Please press ENTER: "
      cmd="read a"; cmd | getline foo
      close(cmd)
   }

   # print the record number
   printf("\n\n=== THIS is MAIL MESSAGE #%d ===\n\n", msg)

   # iterate through the fields of a given 'record' - every field is a LINE, 
   # because records are 'blank line' separated sequesnce of lines
   for(i=1; i<=NF; i++) {

     # if a record field (a line) matches a pattern 'headers' - print that field
     if ( $i ~ headers) print $i
   }
}

# print any OTHER 'record' - this is a shorthand for 'print $0'
1

Works flawlessly now :))).

Its nice to have such a good forum :).

you're welcome....... :wink:

Hello, I thought I would the rest alone, but I cannot make it.

I had to remove "/^From /" before main part of AWK, so it doesnt omit text behind block, which starts with "From ", separated with blank line. But this doesn't work either?

I'm using extra VARIABLE WRITE_OTHER so awk doesn't print unnecessary text between MAIN_HEADER("From ") and SUB_HEADERS. But I want to have written text between SUB_HEADERS and next MAIL(sentence starting with "From ").

This is PETO.AWK, but it doesn't do what I would like to.

BEGIN {
# make 'records' to be separated by blank/empty lines
RS=FS=""

# create a pattern where something starts either one of listed strings
main_header="(^From )"
sub_headers="(^Message-ID:)|(^Date:)|(^From:)|(^To:)|(^Subject:)"

#VARIABLE to help us avoid writing info about sending between header and
#message. 0 - false, 1 - true
}

# If a record starts with 'From ' ...
{
WRITE_OTHER=0

for(i=1; i<=NF; i++) {

    if \( \(msg % 1 == 0 && msg != 1 \) \) \{
            printf "Please press ENTER: "
            cmd="read a"; cmd | getline foo
            close\(cmd\)
    \}

    \# print the record number
    printf\("\\n\\n=== THIS is MAIL MESSAGE \#%d ===\\n\\n", msg\)

    \# iterate through the fields of a given 'record' - every field is a LINE,
    \# because records are 'blank line' separated sequences of lines

    \# if a record field \(a line\) matches a pattern 'headers' - print that field
    if \( $i ~ main_header \) \{
                    WRITE_OTHER = 0
                    print $i
                    msg\+\+
    \}
    else if \( $i ~ sub_headers \) \{
                    WRITE_OTHER = 1
                    print $i
    \}
    else if \( WRITE_OTHER == 1\) \{
                    print $i
    \}

}
}

I've solved it :))...
But be sure I'll be back with another problem :rolleyes:

Hmm..... I don't quite understand what you're after. If you could post a sample input and a desired output with a better brief explanation - it might help.

Also..... when posting code, pls use VB 'code' tags.

I have a similar problem and the seperating of header lines into seperate files works great. How do I get the CONTENTS of each mail also into the respective files. Please Help.

Thanks.

Hey Garric,

I've solved by using a special variable which I set OFF after reading main header ("From <mail.adress>...") and set it on after reading on of sub-headers("From, content-length...").

If this variable is on I write all input on the output => therefore the message too. However, there is more content in /var/mail/user than just this...especially when you get mail from ...@gmail.com. So I am also checking for banned_headers,which I don't want to have on output, and I skip those records, so I really get the HEADERS+MESSAGE.

Hope this helps.

Peto