Skip to content

Instantly share code, notes, and snippets.

@dullgiulio
Created March 24, 2011 21:13
Show Gist options
  • Save dullgiulio/885906 to your computer and use it in GitHub Desktop.
Save dullgiulio/885906 to your computer and use it in GitHub Desktop.
Trivial mailq output parser in PHP.
<?php
/**
* Simple example PHP code to parse "mailq" output. Useful if you want to show
* the mail queue status through some web service.
*
* Notice that you'll need a mail server (sendmail or, better, postfix) to be
* running on the same machine as your webserver (often that's less that
* optimal.)
*
* If this doesn't work, be sure to check that you have sufficient permissions
* to run mailq succesfully as your webserver user.
*
* - Giulio Iotti <giulio@pilv.it>
*/
$results = array();
$current_object = null;
// Get old locale to be later restored. XXX: Changing locale is not thread safe.
$old_locale = getlocale(LC_ALL);
// Set to use no locale.
setlocale(LC_ALL, 'C');
$pipe = popen($mailq_path, 'r');
while($pipe) {
$line = fgets($pipe);
if ($line === false)
break;
// First and last summary lines are the only ones beginning with a dash.
if (strncmp($line, '-', 1) === 0)
continue;
$line = trim();
// Append the current object to the objects list. No last-object problem,
// as we certainly have one empty line before the end.
if (!$line) {
if ($current_object) {
$results[] = $current_object;
$current_object = null;
}
}
// This could be much better so easily (eg: insert months, remove duplications, etc.)
$res = preg_match('/^([A-Z0-9]{1,20})\s+([1-9][0-9]*)\s+((Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+[A-Za-z]{3}\s+[0-9]{2}\s+[0-9]{2}\:[0-9]{2}\:[0-9]{2})\s+([^ ]+)\s*$/', $line, $matches);
if ($res) {
// Insert message ID and other data into the object.
// It will be competed afterwards.
$current_object = array(
'id' => $matches[1],
'size' => intval($matches[2]),
'date' => strftime($matches[3]),
'sender' => $matches[5],
'failed' => false,
'recipients' => ''
);
} else {
// Parse error lines and recipients in lines following the message ID.
if ($current_object) {
if (strncmp($line, '(host ', 6) === 0) {
$current_object['failed'] = substr($line, 6, strlen($line)-7);
} else {
$current_object['recipients'] .= trim($line);
}
}
}
}
pclose($pipe);
setlocale(LC_ALL, $old_locale);
var_dump($results);
exit(1);
@ywarnier
Copy link

Any license you might want to set on this so I can re-use it freely as part of a GPL app? If you set it to LGPL or MIT license, that would be excellent.
It's not to reuse "as is" (obsviously) but to extend on that and be sincere about the origin (I'm sure this will pretty much save me 1 or 2 hours of figuring it out).

@ywarnier
Copy link

On a typical Linux server, can you automatically "get" the mailq path automatically? I guess you use /var/log/mail.log, right? (it is missing in your script)

@ywarnier
Copy link

Nevermind, it is not functional at all. I didn't get that from the title. Thanks for the concept though.

@fser
Copy link

fser commented Nov 15, 2014

Quoting mailq's manpage:

 The queue ID string is followed by an optional status character:
              *      The message is in the active queue, i.e. the message is selected for delivery.
              !      The message is in the hold queue, i.e. no further delivery attempt will  be  made until the mail is taken off hold.

You don't match those status flags :)

@rich9000
Copy link

rich9000 commented Feb 28, 2018

$mailq = explode("\n",trim(shell_exec("mailq")));

array_shift($mailq);
array_pop($mailq);

foreach ($mailq as $line){
	
	
	if(trim($line) == '') continue;
	
	$line = trim($line);

    // This could be much better so easily (eg: insert months, remove duplications, etc.)
    $res = preg_match('/^([A-Z0-9]{1,20})\s+([1-9][0-9]*)\s+((Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+[A-Za-z]{3}\s+[0-9]{2}\s+[0-9]{2}\:[0-9]{2}\:[0-9]{2})\s+([^ ]+)\s*$/', $line, $matches);
    if ($res) {
        
        $id = $matches[1];
        $current_object = array(
                'id' => $matches[1],
                'size' => intval($matches[2]),
                'date' => strftime($matches[3]),
                'sender' => $matches[5],
                'failed' => false,
                'recipients' => ''
        );
    } else {
    	
        // Parse error lines and recipients in lines following the message ID.
        if ($current_object) {
                    	
        	if (strpos(">$line", '(')==1) {
        	//if (strncmp($line, '(host ', 6) === 0) {
                $current_object['failed'] = true;
                $current_object['error'] = $line;
            } else {
                $current_object['recipients'][] = $line;
            }
        }
    }
    
    $results[$id] = $current_object;

}
    
    var_dump($results);

@kepon85
Copy link

kepon85 commented Mar 21, 2023

Thank's for this script, it's ok for me :

> $mailq_path='/usr/bin/mailq';
$results = array();
$current_object = null;
...
<    $line = trim();
>    $line = trim($line);

@kepon85
Copy link

kepon85 commented Apr 12, 2023

Thank's
My adaptation :

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment