GREPMAIL(1p)
๐ GREPMAIL(1p) ๐
okay bestie, welcome to GREPMAIL(1p) โ straight out of the User Contributed Perl Documentation section, and yes it's giving legend behavior. grab a snack, we're doing this together ๐
โจ NAME โจ
grepmail โ search mailboxes for mail matching a regular expression ๐๐
๐ธ SYNOPSIS ๐ธ
grepmail [--help|--version] [-abBDFhHilLmrRuvVw] [-C <cache-file>]
[-j <status>] [-s <sizespec>] [-d <date-specification>]
[-X <signature-pattern>] [-Y <header-pattern>]
[[-e] <pattern>|-E <expr>|-f <pattern-file>] <files...>
๐ฆ DESCRIPTION ๐ฆ
so basically grepmail goes looking through your mail messages for a pattern, and then prints the messages it found on standard out. that's it. that's the whole vibe โจ
by default, grepmail looks in both the header and the body for the pattern you gave it. thorough queen ๐
when you redirect the output to a file, what you get is another mailbox โ which can then be handled by standard User Agents like elm, or even fed as input into another instance of grepmail. it's mailboxes all the way down, no cap ๐
heads up bestie: at least one of-E,-e,-d,-s, or-umust be specified. the pattern is optional if-d,-s, and/or-uis used. the-eflag is optional if there is no file whose name is the pattern. and the-Eoption can be used to specify complex search expressions involving logical operators (more on that below ๐).
if a mailbox can't be found, grepmail first searches the directory specified by the MAILDIR environment variable (if one is defined), and then searches the $HOME/mail, $HOME/Mail, and $HOME/Mailbox directories. it's persistent. it's dedicated. it's the main character ๐ซถ
๐ OPTIONS AND ARGUMENTS ๐
ngl, a lot of these options and arguments are analogous to those of grep. iconic family lineage ๐
๐ pattern
the pattern to search for in the mail message. it can be any Perl regular expression, but you should quote it on the command line to protect against globbing (that's shell expansion, and she WILL expand on you ๐ญ).
to search for more than one pattern, use the form "(pattern1|pattern2|...)".
note that complex pattern features such as "(?>...)" require that you use a version of perl which supports them. and you can use the pattern "()" to indicate that you do not want to match anything at all โ which is genuinely so useful if you just want to initialize the cache without printing any output. sneaky. efficient. obsessed ๐
๐ฌ mailbox
mailboxes must be traditional, UNIX "/bin/mail" mailbox format.
the mailboxes may be compressed by gzip, bzip2, lzip or xz โ in which case the associated compression tool must be installed on the system, as well as a recent version of the Mail::Mbox::MessageParser Perl module that supports the format. no module, no compression party, sorry ๐
if no mailbox is specified, it takes input from stdin, which can be compressed or not.
fr fr important: grepmail's behavior is undefined when ASCII and binary data is piped together as input. do not do that. just don't. ๐
the options, one by one, slay by slay โจ
-aโ use arrival date instead of sent date.-bโ asserts that the pattern must match in the body of the email.-Bโ print the body, but with only minimal headers:'From ','From:','Subject:','Date:'. this flag can be used with-H, in which case it will print only short headers and no email bodies.-Cโ specifies the location of the cache file. the default is$HOME/.grepmail-cache.-Dโ enable debug mode, which prints diagnostic messages. (she's telling you everything, bestie ๐ฃ๏ธ)-eโ explicitly specify the search pattern. this is useful for specifying patterns that begin with-, which would otherwise be interpreted as a flag. protecting you from your own chaos ๐ซถ-fโ obtain patterns from FILE, one per line. the empty file contains zero patterns, and therefore matches nothing. (zero patterns = zero matches, math is math ๐งฎ)-Fโ forcegrepmailto process all files and streams as though they were mailboxes. (i.e. skip checks for non-mailbox ASCII files or binary files that don't look like they are compressed using known schemes.)-hโ asserts that the pattern must match in the header of the email.-Hโ print the header but not the body of matching emails.-iโ make the search case-insensitive (by analogy togrep -i).-jโ asserts that the email"Status:"header must contain the given flags. order and case are not important, so use-j ARor-j rato search for emails which have been read and answered. lowercase? uppercase? she does not care ๐-lโ output the names of files having an email matching the expression (by analogy togrep -l).-Lโ follow symbolic links. (implies-R)-Mโ causesgrepmailto ignore non-text MIME attachments. this removes false positives resulting from binaries encoded as ASCII attachments. bye bye fake matches ๐-mโ append"X-Mailfolder: <folder>"to all email headers, indicating which folder contained the matched email. receipts included ๐งพ-nโ prefix each line with line number information. if multiple files are specified, the filename will precede the line number.
NOTE: when used in conjunction with-m, theX-Mailfolderheader has the same line number as the next (blank) line. yes that's a little weird, no it's not a typo ๐
-qโ quiet mode. suppress the output of warning messages about non-mailbox files, directories, etc. shhh ๐คซ-rโ generate a report of the names of the files containing emails matching the expression, along with a count of the number of matching emails.-Rโ causesgrepmailto recurse any directories encountered. down down down we go ๐-Sโ ignore signatures. the signature consists of everything after a line consisting of"-- ".-uโ output only unique emails, by analogy tosort -u.grepmaildetermines email uniqueness by theMessage-IDheader.-vโ invert the sense of the search, by analogy togrep -v. this results in the set of emails printed being the complement of those that would be printed without the-vswitch. plot twist ๐-Vโ print the version and exit.-wโ search for only those lines which contain the pattern as part of a word group. that is, the start of the pattern must match the start of a word, and the end of the pattern must match the end of a word. (note that the start and end need not be for the same word.)
if you're familiar with Perl regular expressions, this flag simply puts a "\b" before and after the search pattern. cute little word boundaries ๐
-Xโ specify a regular expression for the signature separator. by default this pattern is'^-- $'.
๐ -d โ date specs, the whole thing
date specifications must be of the form of:
- a date like
"today","yesterday","5/18/93","5 days ago","5 weeks ago", - OR
"before","after", or"since", followed by a date as defined above, - OR
"between <date> and <date>", where<date>is defined as above.
simple date expressions will first be parsed by Date::Parse. if this fails, grepmail will attempt to parse the date with Date::Manip, if the module is installed on the system. use an empty pattern (i.e. -d "") to find emails without a "Date: ..." line in the header. ghost emails, found ๐ป
date specifications without times are interpreted as having a time of midnight of that day (which is the morning), except for "after" and "since" specifications, which are interpreted as midnight of the following day. for example, "between today and tomorrow" is the same as simply "today", and returns emails whose date has the current day. ("now" is interpreted as "today".) the date specification "after July 5th" will return emails whose date is midnight July 6th or later. the math is mathing โจ
๐ -E โ complex search expressions
specify a complex search expression using logical operators. the current syntax allows the user to specify search expressions using Perl syntax. three values can be used: $email (the entire email message), $email_header (just the header), or $email_body (just the body). a search is specified in the form "$email =~ /pattern/", and multiple searches can be combined using "&&" and "||" for "and" and "or". build-a-search workshop ๐ ๏ธโจ
for example, the expression
$email_header =~ /^From: .*\@coppit.org/ && $email =~ /grepmail/i
will find all emails which originate from coppit.org (you must escape the "@" sign with a backslash), and which contain the keyword "grepmail" anywhere in the message, in any capitalization. look at her go ๐
not compatible, periodt:-Eis incompatible with-b,-h, and-e.-i,-M,-S, and-Yhave not yet been implemented.
NOTE: the syntax of search expressions may change in the future. in particular, support for size, date, and other constraints may be added. the syntax may also be simplified in order to make expression formation easier to use (and perhaps at the expense of reduced functionality). so likeโฆ screenshot this, bestie ๐ธ
๐ -s โ size specs
return emails which match the size (in bytes) specified with this flag. note that this size includes the length of the header.
size constraints must be of the form of:
12345: match size of exactly12345<12345,<=12345,>12345,>=12345: match size less than, less than or equal, greater than, or greater than or equal to1234510000-12345: match size between10000and12345inclusive
๐ง -Y โ header patterns
specify a pattern which indicates specific headers to be searched. the search will automatically treat headers which span multiple lines as one long line. this flag implies -h.
in the style of procmail, special strings in the pattern will be expanded as follows:
if the regular expression contains "^TO:" it will be substituted by
^((Original-)?(Resent-)?(To|Cc|Bcc)|(X-Envelope|Apparently(-Resent)?)-To):
which should match all headers with destination addresses.
if the regular expression contains "^FROM_DAEMON:" it will be substituted by
(^(Mailing-List:|Precedence:.*(junk|bulk|list)|To: Multiple recipients of |(((Resent-)?(From|Sender)|X-Envelope-From):|>?From )([^>]*[^(.%@a-z0-9])?(Post(ma?(st(e?r)?|n)|office)|(send)?Mail(er)?|daemon|m(mdf|ajordomo)|n?uucp|LIST(SERV|proc)|NETSERV|o(wner|ps)|r(e(quest|sponse)|oot)|b(ounce|bs\.smtp)|echo|mirror|s(erv(ices?|er)|mtp(error)?|ystem)|A(dmin(istrator)?|MMGR|utoanswer))(([^).!:a-z0-9][-_a-z0-9]*)?[%@>\t ][^<)]*(\(.*\).*)?)?
which should catch mails coming from most daemons.
if the regular expression contains "^FROM_MAILER:" it will be substituted by
(^(((Resent-)?(From|Sender)|X-Envelope-From):|>?From)([^>]*[^(.%@a-z0-9])?(Post(ma(st(er)?|n)|office)|(send)?Mail(er)?|daemon|mmdf|n?uucp|ops|r(esponse|oot)|(bbs\.)?smtp(error)?|s(erv(ices?|er)|ystem)|A(dmin(istrator)?|MMGR))(([^).!:a-z0-9][-_a-z0-9]*)?[%@>\t][^<)]*(\(.*\).*)?)?$([^>]|$))
(a stripped down version of "^FROM_DAEMON:"), which should catch mails coming from most mailer-daemons.
so, to search for all emails to or from "Andy":
grepmail -Y '(^TO:|^From:)' Andy mailbox
๐ the rest
--helpโ print a help message summarizing the usage.--โ all arguments following--are treated as mail folders. everything after is just folders, no more flags, we're done with options ๐
โฆand that's part one, bestie!! there's more coming so don't go anywhere ๐ซถโจ
โจ EXAMPLES โจ
okay so like, examples? we love a practical demo. here's every single one from the page, no cap. ๐
๐ Count the number of emails
(. matches every email.)
grepmail -r . sent-mail
๐ Get all email between 2000 and 3000 bytes about books
grepmail books -s 2000-3000 sent-mail
๐๏ธ Get all email that you mailed yesterday
grepmail -d yesterday sent-mail
๐ฌ Get all email that you mailed before the first thursday in June 1998 that pertains to research (requires Date::Manip)
grepmail research -d "before 1st thursday in June 1998" sent-mail
๐ Get all email that you mailed before the first of June 1998 that pertains to research
grepmail research -d "before 6/1/98" sent-mail
๐ซ Get all email you received since 8/20/98 that wasn't about research or your job, ignoring case
grepmail -iv "(research|job)" -d "since 8/20/98" saved-mail
๐ง Get all email about mime but not about Netscape. Constrain the search to match the body, since most headers contain the text "mime"
grepmail -b mime saved-mail | grepmail Netscape -v
๐ Print a list of all mailboxes containing a message from Rodney. Constrain the search to the headers, since quoted emails may match the pattern
grepmail -hl "^From.*Rodney" saved-mail*
โ๏ธ Find all emails with the text "Pilot" in both the header and the body
grepmail -hb "Pilot" saved-mail*
๐ข Print a count of the number of messages about grepmail in all saved-mail mailboxes
grepmail -br grepmail saved-mail*
๐๏ธ Remove any duplicates from a mailbox
grepmail -u saved-mail
๐ฆ Convert a Gnus mailbox to mbox format
grepmail . gnus-mailbox-dir/* > mbox
๐ฌ Search for all emails to or from an address (taking into account wrapped headers and different header names)
grepmail -Y '(^TO:|^From:)' my@email.address saved-mail
๐ฎ Find all emails from postmasters
grepmail -Y '^FROM_MAILER:' . saved-mail
๐ธ FILES ๐ธ
grepmail will not create temporary files while decompressing compressed archives. the last version to do this was 3.5. while the new design uses more memory, the code is much simpler, and there is less chance that email can be read by malicious third parties. memory usage is determined by the size of the largest email message in the mailbox. ๐ง ๐
๐ฆ ENVIRONMENT ๐ฆ
the MAILDIR environment variable can be used to specify the default mail directory. this directory will be searched if the specified mailbox can not be found directly.
the HOME environment variable is also used to find mailboxes if they can not be found directly. it is also used to store grepmail state information such as its cache file.
๐ BUGS AND LIMITATIONS ๐
Patterns containing $ may cause problems
currently I look for $ followed by a non-word character and replace it with the line ending for the current file (either \n or \r\n). this may cause problems with complex patterns specified with -E, but I'm not aware of any. ๐ญ
Mails without bodies cause problems
according to RFC 822, mail messages need not have message bodies. I've found and removed one bug related to this. I'm not sure if there are others. ๐
Complex single-point dates not parsed correctly
if you specify a point date like "September 1, 2004", grepmail creates a date range that includes the entire day of September 1, 2004. if you specify a complex point date such as "today", "1st Monday in July", or "9/1/2004 at 0:00" grepmail may parse the time incorrectly.
the reason for this problem is that Date::Manip, as of version 5.42, forces default values for parsed dates and times. this means that grepmail has a hard time determining whether the user supplied certain time/date fields. (e.g. Did Date::Manip provide a default time of 0:00, or did the user specify it?) grepmail tries to work around this problem, but the workaround is inherently incomplete in some rare cases.
File names that look like flags cause problems.
in some special circumstances, grepmail will be confused by files whose names look like flags. in such cases, use the -e flag to specify the search pattern. ๐
๐ LICENSE ๐
this code is distributed under the GNU General Public License (GPL) Version 2. see the file LICENSE in the distribution for details. ๐ซถ
๐ AUTHOR ๐
David Coppit <david@coppit.org> โ iconic. ๐
๐ SEE ALSO ๐
check out: elm(1), mail(1), grep(1), perl(1), printmail(1), Mail::Internet(3), procmailrc(5). also: Crocker, D. H., Standard for the Format of Arpa Internet Text Messages, RFC 822. ๐
and that's the whole page, bestie! this is from perl v5.36.0, dated 2023-09-24, and it's GREPMAIL(1p). slay. ๐ โจ
๐ฆ where this page comes from
- debian trixie: grepmail 5.3111-4 ยท GPL-2.0-only
- ubuntu noble: grepmail 5.3111-4 ยท GPL-2.0-only
- ubuntu questing: grepmail 5.3111-4
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms