diff --git a/README.md b/README.md index dc499f6..8453396 100644 --- a/README.md +++ b/README.md @@ -1 +1,46 @@ -# Email warmup bot += Email warmup bot = + +== Installation == + +``` +apt install php-cli php-imap php-mailparse php-net-smtp +git clone https://gitpull.it/source/email-warmup-bot/ +git clone https://gitpull.it/source/php-imap-spooler/ +``` + +``` +cd email-warmup-bot +cp config-example.php config.php +nano config.php +``` + +== Usage == + +``` +./bot.php +``` + +== License == + +``` +# Copyright (c) 2021 Valerio Bozzolan (https://boz.reyboz.it) +# PHP email warmup bot +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +``` diff --git a/autoload.php b/autoload.php index 431adea..ac1fe62 100644 --- a/autoload.php +++ b/autoload.php @@ -1,15 +1,32 @@ imap, $credentials->login, $credentials->password ); // set the callback for every e-mail $spooler->setEmailHandler( function ( $body, $headers, $info ) use ( $credentials ) { message( "connected" ); // complete message $email_raw = $headers . $body; // '' $return_path = null; $subject = null; $parser = mailparse_msg_create(); // MUST be destroyed at the end of the script mailparse_msg_parse( $parser, $email_raw ); $structure = mailparse_msg_get_structure( $parser ); // Ex. ["1", "1.1", "1.2"] foreach( $structure as $part_label ) { // Search among each e-mail part $part = mailparse_msg_get_part( $parser, $part_label ); // Parse a specified part $part_data = mailparse_msg_get_part_data( $part ); // Get parsed part data, header and meta values $headers = $part_data['headers']; // asd $subject = $headers['subject'] ?? null; $return_path = $headers[ 'return-path' ] ?? $headers[ 'from' ] ?? null; if( $return_path ) { // sometime this is a damn array if( is_array( $return_path ) ) { $return_path = $return_path[0]; } break; } } // extract 'something@asd.it' from '' or 'Foo ' $return_path_email = null; if( $return_path ) { $return_path_data = mailparse_rfc822_parse_addresses( $return_path ); foreach( $return_path_data as $email_data ) { // address infos $return_path_address = $email_data['address']; break; } } if( $return_path_address ) { $reply_message = "Ciao bello!\n"; $reply_message .= reply_email( $body ); message( sprintf( "trying to send email from %s to $return_path_address", $credentials->from ) ); //TODO: in reply to // https://stackoverflow.com/questions/45690336/do-all-email-clients-use-in-reply-to-field-in-email-header $result = NetSMTPSender::send( $credentials, $return_path_address, "Re: $subject", $reply_message, $additional_headers = '', $more = '' ); if( $result ) { message( sprintf( "sent email to %s", $return_path_address ) ); } $delete = true; } else { $delete = false; } return $delete; } ); // open the connection $spooler->open(); // just process all and then quit $spooler->processAll(); // close the connection $spooler->close(); message( "wait" ); // wait some time sleep( IMAPBOT_CYCLE_SLEEP ); } } catch( Exception $e ) { printf( "SMTP bot error (%s): %s\n", get_class( $e ), $e->getMessage() ); printf( " Trace: %s\n", $e->getTraceAsString() ); // we can't just stop looping because sometime the user sends a wrong command and we get an Exception // $loop = false; $error = true; } } while( $loop ); /** * Operating system signal handler * * @param $signo int * @param $siginfo mixed */ function sig_handler( $signo, $siginfo ) { // stop looping $GLOBALS['loop'] = false; // eventually close the spooler $GLOBALS['spooler']->close(); // just warn about this signal message( "quit after SIG $signo" ); // quit if( $GLOBALS['error'] ) { exit( 1 ); } else { exit( 0 ); } } /** * Print a message to standard output with a date * * @param string $message */ function message( $message ) { printf( "[%s] %s\n", date( 'c' ), $message ); } function strippa_minchia( $message ) { throw new Exception( "to be implemented asd to strip the minch" ); } /** * asd * >asd */ function reply_email( $message ) { $message = trim( $message ); $message = str_replace( "\n", "\n>", ">$message" ); return $message; } diff --git a/include/class-MailboxCredentials.php b/include/class-MailboxCredentials.php index a8aa974..da67dfb 100644 --- a/include/class-MailboxCredentials.php +++ b/include/class-MailboxCredentials.php @@ -1,43 +1,63 @@ host = $args['host']; $asd->port = $args['port']; $asd->from = $args['from']; $asd->login = $args['login']; $asd->password = $args['password']; $asd->auth = $args['auth']; $asd->debug = $args['debug'] ?? false; $asd->name = $args['name'] ?? $args['from']; $asd->imap = $args['imap']; return $asd; } public function isDebug() { return $this->debug ?? false; } } diff --git a/include/class-MailboxCredentialsCollector.php b/include/class-MailboxCredentialsCollector.php index ad23d1c..ec6da88 100644 --- a/include/class-MailboxCredentialsCollector.php +++ b/include/class-MailboxCredentialsCollector.php @@ -1,15 +1,35 @@ [ 'verify_peer_name' => false, 'verify_peer' => false, ], ]; if( ! ($smtp = new Net_SMTP( $credentials->host, $credentials->port, null, false, 0, $socket_options ) ) ) { error_wp_net_smtp( 'Unable to instantiate Net_SMTP object', $smtp->getUserInfo() ); return false; } if( $credentials->isDebug() ) { $smtp->setDebug( true ); } if( PEAR::isError( $e = $smtp->connect() ) ) { error_wp_net_smtp( 'Error connect', $e->getMessage() ); return false; } if( PEAR::isError( $e = $smtp->auth( $credentials->login, $credentials->password, $credentials->auth, true, '', true ) ) ) { error_wp_net_smtp( 'Error auth', $e->getMessage() ); return false; } if( PEAR::isError( $smtp->mailFrom( $credentials->from ) ) ) { error_wp_net_smtp( 'Error set from', $res->getMessage() ); return false; } foreach( $to as $i => $single_to ) { if( filter_var( $single_to, FILTER_VALIDATE_EMAIL ) === false ) { unset( $to[$i] ); error_wp_net_smtp( 'Wrong e-mail address stripped out', $single_to ); continue; } if( PEAR::isError( $res = $smtp->rcptTo( $single_to ) ) ) { error_wp_net_smtp( 'Error set To', $res->getMessage() ); return false; } } if( count( $to ) === 0 ) { error_wp_net_smtp( 'No email sent', 'no addresses' ); return false; } $headers = [ 'MIME-Version' => '1.0', 'Subject' => $subject, 'To' => implode( ',', $to ), 'From' => sprintf( '%s <%s>', $credentials->name, $credentials->from ), 'Content-Type' => sprintf( 'text/plain;charset=%s', 'utf-8' ), 'X-Mailer' => 'Net/SMTP.php via WordPress in Debian GNU/Linux asd', ]; $merge = []; foreach( $headers as $header => $value ) { $value = trim( $value ); $merge[] = sprintf('%s: %s', $header, $value); } $headers = $additional_headers . implode( "\r\n" , $merge ); $error = PEAR::isError( $smtp->data( "$headers\r\n$message" ) ); $smtp->disconnect(); return ! $error; } }