Skip to content

Instantly share code, notes, and snippets.

@tuanphpvn
Forked from Spea/README.md
Created November 27, 2017 11:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tuanphpvn/da74a65c45ebddef9c4131151caf946d to your computer and use it in GitHub Desktop.
Save tuanphpvn/da74a65c45ebddef9c4131151caf946d to your computer and use it in GitHub Desktop.
Script to auto reply emails.

General

This script can be used in conjunction with the ISPmail tutorial and the Roundcube autoreply plugin

Installation

Database setup

Create the following table in the database where you created the tables from the ISPmail tutorial.

CREATE TABLE IF NOT EXISTS `autoresponder` (
  `email` varchar(255) NOT NULL DEFAULT '',
  `from` date NOT NULL DEFAULT '0000-00-00',
  `to` date NOT NULL DEFAULT '0000-00-00',
  `message` text NOT NULL,
  `force_disabled` tinyint(4) NOT NULL DEFAULT '1',
  `subject` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`email`),
  FULLTEXT KEY `message` (`message`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Copy the file

Copy the code from the autoreply.php file and place it in any directory you want. The best would be to create a new user and place the file in it`s home directory

/home/USER/autoreply.php

Configuration

Most of the configuration should be self-explanatory, nevertheless I explain some of them here.

Cycle

This specifies the cycle in which you want to run the script, this has to be the same as the cycle of the cronjob (in this case 5 minutes). Based on the cycle the script determines if an auto-reply for a message should be send or not.

Imagine the following settings for the cycles:

Script | Cronjob  | Result
10 min | 5 min    | Auto reply will be send twice for the same email
5 min  | 10 min   | Only emails which arrived 5 minutes before the cronjob gets executed will be auto-replied
5 min  | 5 min    | Auto reply will be send exactly one time
<?php
/* General */
$conf['cycle'] = 5 * 60; # seconds

Path to mails

This specifies the path where new mails are stored. When you followed the ISPmail tutorial you can leave it as is.

<?php
/* The path to the mail directory */
$conf['mailbox_path'] = "/var/vmail/%domain%/%user%/Maildir/new";

Logging

If you want logging to be enabled, set write_log to true and specify the path to the log file.

<?php
/* Logging */
$conf['log_file_path'] = "/var/log/autoreply";
$conf['write_log'] = true;

Cronjob

The script has to run continous and in a specific interval. Every time the script is executed, it checks for new mails in the mailboxes where an auto reply is configured.

Use the following cronjob to run the script every 5 minutes.

*/5 * * * * /home/USER/autoreply.php

Add new auto replies

To add a new auto reply, just add a new record in the table we created before.

#!/usr/bin/php -q
<?php
/*
goldfish - the PHP auto responder for postfix
Copyright (C) 2007-2008 by Remo Fritzsche
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
(c) 2012 Martin Parsiegla (Refactored)
(c) 2007-2009 Remo Fritzsche (Main application programmer)
(c) 2009 Karl Herrick (Bugfix)
(c) 2007-2008 Manuel Aller (Additional programming)
Version 1.0-STABLE
*/
if (version_compare(PHP_VERSION, "5.3.3") == -1) {
echo "Install PHP 5.3.3 or newer (current version is ". phpversion() .")";
exit;
}
/* General */
$conf['cycle'] = 5 * 60;
/* Logging */
$conf['log_file_path'] = "/var/log/autoreply";
$conf['write_log'] = true;
/* The path to the mail directory */
$conf['mailbox_path'] = "/var/vmail/%domain%/%user%/Maildir/new";
/* Database information */
$conf['mysql_host'] = "localhost";
$conf['mysql_user'] = "mailuser";
$conf['mysql_password'] = "password";
$conf['mysql_database'] = "mailserver";
/* Database Queries */
# This query has to return the following fields from the autoresponder table: `from`, `to`, `email`, `message`
$conf['q_forwardings'] = "SELECT `email`, `message`, `subject` FROM `autoresponder` WHERE `force_disabled` = 0 AND NOW() BETWEEN `from` AND `to`;";
class Logger
{
private $str;
private $conf;
public function __construct($conf)
{
$this->conf = $conf;
}
function addLine($str)
{
$str = date("Y-m-d h:i:s") . " " . $str;
$this->str .= "\n$str";
echo $str . "\n";
}
function writeLog()
{
if (!$this->conf['write_log']) return;
if (is_writable($this->conf['log_file_path'])) {
$this->addLine("--------- End execution ------------");
if (false === file_put_contents($this->conf['log_file_path'], $this->str, FILE_APPEND)) {
echo "Cannot write to file";
exit;
} else {
echo "Wrote log successfully.";
}
} else {
echo "Error: The log file is not writeable.\n";
}
}
}
$log = new Logger($conf);
// establish database connection
try {
$dsn = 'mysql:dbname=' . $conf['mysql_database'] . ';host=' . $conf['mysql_host'];
$pdo = new PDO($dsn, $conf['mysql_user'], $conf['mysql_password']);
$log->addLine("Connection to database established successfully");
} catch (PDOException $ex) {
$log->addLine("ERROR: Could not connect to database: " . $e->getMessage());
$log->writeLog();
exit();
}
// Corresponding email addresses
$result = $pdo->query($conf['q_forwardings']);
if (false === $result) {
$log->addLine("Error in query " . $conf['q_forwardings'] . "\n" );
exit();
}
$accounts = array();
foreach ($result as $row) {
$domain = str_replace('@', '', strstr($row['email'], '@'));
$user = strstr($row['email'], '@', true);
$row['user'] = $user;
$row['path'] = str_replace(array('%user%', '%domain%'), array($user, $domain), $conf['mailbox_path']);
$accounts[] = $row;
}
// check for new emails
foreach ($accounts as $account) {
$path = $account['path'];
try {
$dir = new DirectoryIterator($path);
} catch(Exception $ex) {
// Path could not be opened, proceed with next value
$log->addLine("The directory '". $path ."' could not be opened.");
continue;
}
foreach ($dir as $fileInfo) {
if ($fileInfo->isDot()) {
continue;
}
if (time() - $fileInfo->getMTime() - $conf['cycle'] >= 0) {
continue;
}
$file = $fileInfo->openFile('r');
$wholeFile = '';
while (!$file->eof()) {
$line = $file->current();
$line = trim($line);
$wholeFile .= $line;
if (substr($line, 0, 12) == 'Return-Path:') {
$returnpath = substr($line, strpos($line, '<') + 1, strpos($line, '>') - strpos($line, '<') - 1) . "\n";
}
if (substr($line, 0, 5) == 'From:' && strstr($line, "@")) {
$address = substr($line, strpos($line, '<') + 1, strpos($line, '>') - strpos($line, '<') - 1) . "\n";
break;
} elseif (substr($line, 0, 5) == 'From:' && !strstr($line, "@") && !empty ($returnpath)) {
$address = $returnpath;
break;
}
$file->next();
}
if (empty($address)) {
$log->addLine("Error, could not parse mail $path");
continue;
}
$headers = "From: " . $account['user'] . "<" . $account['email'] . ">";
// Check if mail is allready an answer:
if (strstr($wholeFile, $account['message'])) {
$log->addLine("Mail from ". $account['email'] ." allready answered");
break;
}
// strip the line break from $address for checks
// fix by Karl Herrick, thank's a lot
if (substr($address, 0, strlen($address) - 1) == $account['email']) {
$log->addLine("Email address from autoresponder table is the same as the intended recipient! Not sending the mail!");
break;
}
$log->addLine("Successfully sent email to ". $address);
mail($address, $account['subject'], $account['message'], $headers);
}
}
$log->writeLog($conf);
echo "End execution.";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment