How to extract email headers extending on multiple lines from file

江枫思渺然 提交于 2020-12-06 20:23:03

问题


I am trying to extract the To header from an email file using sed on linux.

The problem is that the To header could be on multiple lines.

e.g:

To: name1@mydomain.org, name2@mydomain.org,
    name3@mydomain.org, name4@mydomain.org, 
    name5@mydomain.org
Message-ID: <46608700.369886.1549009227948@domain.org>

I tried the following:

sed -n -e '/^[Tt]o: / { N; p; }' _message_file_ |
    awk '{$1=$1;printf("%s ",$0)};NR%2==0{print ""}'

The sed command extracts the line starting with To and next line. I pipe the output to awk to put everything on a single line.

The full command outputs in one line:

To: name1@mydomain.org, name2@mydomain.org, name3@mydomain.org, name4@mydomain.org

I don't know how to keep going and test if the next line starts with whitespace and add it to the result.

What I want is all the addresses

To: name1@mydomain.org, name2@mydomain.org, name3@mydomain.org, name4@mydomain.org, name5@mydomain.org

Any help will be appreciated.


回答1:


formail is a good solution but here's how to do it with sed:

sed -e '/^$/q;/^To:/!d;n;:c;/^\s/!d;n;bc' message_file 
  • /^$/q; - (optional) quit if we run out of headers
  • /^To:/!d; - if not a To: header, stop processing this line
  • n; - otherwise, implicitly print it, and load next line
  • :c; - c is a label we can branch to
  • /^\s/!d; - if not a contination, stop processing this line
  • n; - otherwise, implicitly print it, and load next line
  • bc - branch back to label c (ie. loop)



回答2:


I did it like this:

cat _message_file | formail -X To: | awk '{$1=$1;printf("%s ",$0)};NR%2==0{print ""}'

Or:

formail -X To: < _message_file | awk '{$1=$1;printf("%s ",$0)};NR%2==0{print ""}'



回答3:


This might work for you (GNU sed):

sed -n '/^To:/{:a;N;/^ /Ms/\s*\n\s*/ /;ta;P}' file

Turn off implicit printing by using the -n option. Gather up the lines starting with white space, removing white space either side of the newline and replace it by a single space, starting from the line that begins To:. When matching fails, print the first line in the pattern space.

To print addresses as is, use:

sed '/^\S/h;G;/^To:/MP;d' file



回答4:


Both formail and reformail have a -c option to do exactly that.

From man reformail:

-c   Concatenate multi-line headers. Headers split on multiple lines
     are combined into a single line.

So you don't need to pipe the output to awk, and can just do

reformail -c -X To: < $your_message_file

However, emails normally use CRLF line endings, and the output on screen may be garbled because of the CR characters. To remove them, you can use Perl's generic \R line ending in a regex on the output :

reformail -c -X To: < $your_message_file | perl -pe 's/\R/\n/g'

or do it on the input if you prefer:

perl -pe 's/\R/\n/g' $your_message_file | reformail -c -X To:

On Debian and derived systems like Ubuntu, you can install them with

  • apt install maildrop for reformail, which is part of Courier's maildrop

  • or apt install procmail for formail (but procmail seems to be abandoned now).



来源:https://stackoverflow.com/questions/54481930/how-to-extract-email-headers-extending-on-multiple-lines-from-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!