jay5r Posted May 12, 2020 Posted May 12, 2020 I've got a 10 year old site that's got about 65,000 users. Over the years a lot of the member email addresses have gone bad. The problem is I can't find a way to stop emails going to bad email addresses. Yes, there are horribly complicated ways to do it, but they're not practical when there are many hundreds of bad emails. I'm aware of Mail Bouncer, but when I tried it I found that none of it's supported mail services allow adult content. So it's not an option for me. Recently I tried the "Force User to Change Email Address" plugin, which unvalidates the email. But IP.Board keeps sending emails even though the email addresses are no longer validated. IMHO, the only email that should be sent to an unvalidated email address is an email to validate the email address. I'm not asking for something that will comb a mailbox and parse errors. I just want a simple way to turn off the emails once I have a list of problem emails. Does anyone have a suggestion?
jay5r Posted May 12, 2020 Author Posted May 12, 2020 @Adriano Faria – as I mentioned, I'm unable to use Mail Bouncer.
Square Wheels Posted May 12, 2020 Posted May 12, 2020 I'd love a solution for this too. I have a site that is 16+ years old, I get a lot of bounces. Sadly I got to the notifications of each of them and turn off all of their notifications. Then I move them to a group called Bounced Member, this displays a large red banner asking them to update their email and let me know. It's a huge amount of work and a colossal waste of time. I do it in hopes not to get black listed.
CoffeeCake Posted May 12, 2020 Posted May 12, 2020 @Square Wheels: If you use one of the third party mail services that the Mail Bouncer application Adriano linked above supports, it does exactly what you want. Unfortunately jay5r is probably using either an unsupported service or local smtp due to his content.
Square Wheels Posted May 12, 2020 Posted May 12, 2020 35 minutes ago, Paul E. said: @Square Wheels: If you use one of the third party mail services that the Mail Bouncer application Adriano linked above supports, it does exactly what you want. Unfortunately jay5r is probably using either an unsupported service or local smtp due to his content. Â Â Mine is local email too.
Maxxius Posted May 13, 2020 Posted May 13, 2020 (edited) I have went thru the same thing. Here's my brutal way of doing it. Download all the members list from ACP. Save it as CSV and let it go thru www.neverbounce.com it will mark invalid email boxes. It costs a bit. You can also employ other email checking services. neverbounce isnt the only one. Then use information in this topic to disable invalid emails in bulk in your system and run queries in phpmyadmin. I managed to filter out almost 34k worth of emails collected throughout 14 years. Took me 1,5 days of work. Also note that neverbounce has trouble telling yahoo emails if they are valid or not. I noticed that even if it marks address as okay it a lot of them might still bounce. Â Edited May 13, 2020 by Maxxius Sonya* and Square Wheels 2
jay5r Posted May 13, 2020 Author Posted May 13, 2020 Unless someone comes up with a better idea, here's what I'm thinking of doing… Writing something in PHP to scan the email inbox that receives the bounce notifications. I'll use key phrases in the email to determine if it's a case of a invalid email address or a full mailbox. For now I'll ignore the ones that are basically "we don't like you". I'll then make a SQL connection to my IP.Board database and modify the email address. I'll append ".hf" to the hard fails (invalid email address), and .YYYYMMDD.sf to the ones where their mailbox is full. IP.Board will still attempt to send the email, but it will fail. But it will fail in a way that won't bother legit email servers. That will preserve my reputation with those email providers. The YYYYMMDD in the soft fails will indicate the date of the last failure. I can then write a routine that will go through and search for all the ".sf" email addresses, and if they're more than a week old, I'll strip off the .YYYYMMDD.sf which will let mail be sent to them again. If their mailbox is still full, then the process repeats itself. I'll also (try to) write a Javascript that I'll include on each page that inserts a warning banner at the top of the page if the user's email ends in .hf or .sf warning them that action is needed on their part. But seriously, Invision should make this an easier process. It's a bit ridiculous that we can't just specify a list of email addresses that need their emails turned off (except for validation emails). Maxxius 1
stoo2000 Posted May 13, 2020 Posted May 13, 2020 4 minutes ago, jay5r said: Unless someone comes up with a better idea, here's what I'm thinking of doing… Writing something in PHP to scan the email inbox that receives the bounce notifications. I'll use key phrases in the email to determine if it's a case of a invalid email address or a full mailbox. For now I'll ignore the ones that are basically "we don't like you". I'll then make a SQL connection to my IP.Board database and modify the email address. I'll append ".hf" to the hard fails (invalid email address), and .YYYYMMDD.sf to the ones where their mailbox is full. IP.Board will still attempt to send the email, but it will fail. But it will fail in a way that won't bother legit email servers. That will preserve my reputation with those email providers. The YYYYMMDD in the soft fails will indicate the date of the last failure. I can then write a routine that will go through and search for all the ".sf" email addresses, and if they're more than a week old, I'll strip off the .YYYYMMDD.sf which will let mail be sent to them again. If their mailbox is still full, then the process repeats itself. I'll also (try to) write a Javascript that I'll include on each page that inserts a warning banner at the top of the page if the user's email ends in .hf or .sf warning them that action is needed on their part. But seriously, Invision should make this an easier process. It's a bit ridiculous that we can't just specify a list of email addresses that need their emails turned off (except for validation emails). If you wanted to, you could still combine/integrate this with Mail Bouncer. You could do something like this... <?php ... your code... include '/ips4path/init.php'; \IPS\Dispatcher\External::i(); $bounce = 'hard'; $email = 'exampleemail@gmail.com'; $member = \IPS\Member::load( $email, 'email' ); /* Check it's a real account */ if( $member->member_id ) { if( $bounce == 'hard' ) { $member->bouncerHardBounce( time() ); //or use the time from the bounce itself } elseif ( $bounce == 'soft' ) { $member->bouncerSoftBounce( time() ); //or use the time from the bounce itself } elseif( $bounce == 'spam' ) { $member->bouncerSpam( time() ); //or use the time from the bounce itself } } Alternatively, if you're processing a lot of bounces at the same time (i.e. a periodic sweep of a mailbox) you can queue the bounces instead and let the app process them in the background. <?php .... your code include '/ips4path/init.php'; \IPS\Dispatcher\External::i(); foreach( $bounces as $bounce ) { /* Create Bounce */ $bounce = new \IPS\bouncer\Bounce; $bounce->email = $event['email']; $bounce->classification = $bounce['type']; // 'hard', 'soft', 'spam' $bounce->reason = $bounce['reason']; $bounce->timestamp = $bounce['timestamp']; $bounce->save(); } /* Queue the process */ \IPS\Task::queue( 'bouncer', 'ProcessBounces', array( 'class' => 'placeholder' ), 5, array('class') );  jay5r 1
Square Wheels Posted May 13, 2020 Posted May 13, 2020 5 minutes ago, stoo2000 said: If you wanted to, you could still combine/integrate this with Mail Bouncer. You could do something like this... <?php ... your code... include '/ips4path/init.php'; \IPS\Dispatcher\External::i(); $bounce = 'hard'; $email = 'exampleemail@gmail.com'; $member = \IPS\Member::load( $email, 'email' ); /* Check it's a real account */ if( $member->member_id ) { if( $bounce == 'hard' ) { $member->bouncerHardBounce( time() ); //or use the time from the bounce itself } elseif ( $bounce == 'soft' ) { $member->bouncerSoftBounce( time() ); //or use the time from the bounce itself } elseif( $bounce == 'spam' ) { $member->bouncerSpam( time() ); //or use the time from the bounce itself } } Alternatively, if you're processing a lot of bounces at the same time (i.e. a periodic sweep of a mailbox) you can queue the bounces instead and let the app process them in the background. <?php .... your code include '/ips4path/init.php'; \IPS\Dispatcher\External::i(); foreach( $bounces as $bounce ) { /* Create Bounce */ $bounce = new \IPS\bouncer\Bounce; $bounce->email = $event['email']; $bounce->classification = $bounce['type']; // 'hard', 'soft', 'spam' $bounce->reason = $bounce['reason']; $bounce->timestamp = $bounce['timestamp']; $bounce->save(); } /* Queue the process */ \IPS\Task::queue( 'bouncer', 'ProcessBounces', array( 'class' => 'placeholder' ), 5, array('class') );  Let's say I have no php skills, would you be able to create a tool that could move all bounced emails to a new group and remove all of their email notifications? That would be beyond amazing. I am using SMTP from my own server. I currently have over 500 bounced emails I am processing one at a time. I go to their preferences, uncheck all of the email notifications, then move them to a bounced member account. It's a bit of a pain. Maxxius and Bluto 2
jay5r Posted May 13, 2020 Author Posted May 13, 2020 @stoo2000 - thanks for that. That could make things easier. I'll give it a shot.
Dean_ Posted May 13, 2020 Posted May 13, 2020 Why is something like this not part of IPS, is there no way of having this within the software if it detects a bounce back and setting that member accordingly? Maxxius, zyx and jay5r 3
Bluto Posted May 14, 2020 Posted May 14, 2020 (edited) Maybe after the Zapier integration? You'll be able to use Mailfloss because their integrated. https://mailfloss.com/tour/  Also you can look at ActiveCampaign plugin which I believe that AC has an email checker, but not sure if @Spanner has it setup to flag email address in IPS which are invalid in AC. You'd have to ask him. Obviously, you'd have to use AC, which is actually an excellent marketing tool.    Edited May 14, 2020 by Bluto
Dean_ Posted May 14, 2020 Posted May 14, 2020 (edited) Might suit some but as I said with Zapier, I refuse to pay yet another subscription to which I think could be a core feature in IPS. I’ve looked into a lot of mail services but it’s far to expensive for my needs and would be wasted on me. Even more so with the recent spam problem with email sharing were me and few others had over 1M emails sent... God knows how much that would’ve cost me! Edited May 14, 2020 by Dean_ jay5r 1
Spanner Posted May 14, 2020 Posted May 14, 2020 6 hours ago, Bluto said: Also you can look at ActiveCampaign plugin which I believe that AC has an email checker, but not sure if @Spanner has it setup to flag email address in IPS which are invalid in AC. You'd have to ask him. Obviously, you'd have to use AC, which is actually an excellent marketing tool. I don't have that function on my integration, but I think I'll can add 😉 Bluto 1
Square Wheels Posted May 14, 2020 Posted May 14, 2020 I too cannot afford to move to a mail service. I have a newsletter program that processes bounces, so I am all set there. If I send a Bulk Mail through the site (which I only do once a year of so), I get about 500 bounces back each time. That's a huge pain to process those. Having this built in would be wonderful. @Charles @Lindy @Matt any chance this is being considered? Maxxius 1
jay5r Posted May 15, 2020 Author Posted May 15, 2020 On 5/13/2020 at 9:21 AM, stoo2000 said: If you wanted to, you could still combine/integrate this with Mail Bouncer. You could do something like this... <?php ... your code... include '/ips4path/init.php'; \IPS\Dispatcher\External::i(); $bounce = 'hard'; $email = 'exampleemail@gmail.com'; $member = \IPS\Member::load( $email, 'email' ); /* Check it's a real account */ if( $member->member_id ) { if( $bounce == 'hard' ) { $member->bouncerHardBounce( time() ); //or use the time from the bounce itself } elseif ( $bounce == 'soft' ) { $member->bouncerSoftBounce( time() ); //or use the time from the bounce itself } elseif( $bounce == 'spam' ) { $member->bouncerSpam( time() ); //or use the time from the bounce itself } } Alternatively, if you're processing a lot of bounces at the same time (i.e. a periodic sweep of a mailbox) you can queue the bounces instead and let the app process them in the background. <?php .... your code include '/ips4path/init.php'; \IPS\Dispatcher\External::i(); foreach( $bounces as $bounce ) { /* Create Bounce */ $bounce = new \IPS\bouncer\Bounce; $bounce->email = $event['email']; $bounce->classification = $bounce['type']; // 'hard', 'soft', 'spam' $bounce->reason = $bounce['reason']; $bounce->timestamp = $bounce['timestamp']; $bounce->save(); } /* Queue the process */ \IPS\Task::queue( 'bouncer', 'ProcessBounces', array( 'class' => 'placeholder' ), 5, array('class') );  Questions about that code… I've figured out how to access the email account receiving the bounce messages and I've parsed the bounces into two arrays – $hardfails and $softfails. I grabbed the code for the 2nd case you specified but it didn't look right to me… Should it be foreach($events as $event)? To me it doesn't make sense to do a new $bounce inside a loop that sets $bounce. Then I figured I'd do it based on your first example, so I came up with this… require_once '/home/httpd/html/mysite.com/public_html/init.php'; echo "<p>Require executed.</p>"; \IPS\Dispatcher\External::i(); foreach ($softfails as $email){ echo "<li>$email – "; ob_flush(); $member = \IPS\Member::load( $email, 'email' ); if( $member->member_id ) { $member->bouncerSoftBounce( time() ); echo "set as soft bounce."; } else { echo "member not found."; } echo "</li>"; } But \IPS\Dispatcher\External::i(); throws a server error (500). Can you give any insight into what I'm doing wrong? Admittedly I'm not all that familiar with programming for IP.Board. Here's what got logged for the error… Error: Call to undefined method stdClass::language() (0) #0 /home/httpd/html/mysite.com/public_html/system/Dispatcher/External.php(64): IPS\Dispatcher\_Standard::baseJs() #1 /home/httpd/html/mysite.com/public_html/system/Dispatcher/External.php(41): IPS\Dispatcher\_External::baseJs() #2 /home/httpd/html/mysite.com/public_html/system/Dispatcher/Dispatcher.php(109): IPS\Dispatcher\_External->init() #3 /home/httpd/html/mysite.com/public_html/bouncers.php(159): IPS\_Dispatcher::i() #4 {main} [To the folks who wanted my source code for parsing the emails, I'll post it when I've got things working and cleaned up.]
Maxxius Posted May 16, 2020 Posted May 16, 2020 Indeed and something like 4 soft bounces turns into hard bounce and member is automatically unsubscribed.
DawPi Posted May 16, 2020 Posted May 16, 2020 (edited) Or at least - validating members does not receive any mails from followed content. Edited May 16, 2020 by DawPi Maxxius 1
stoo2000 Posted May 16, 2020 Posted May 16, 2020 On ‎5‎/‎15‎/‎2020 at 9:14 PM, jay5r said: But \IPS\Dispatcher\External::i(); throws a server error (500). Can you give any insight into what I'm doing wrong? Admittedly I'm not all that familiar with programming for IP.Board. Here's what got logged for the error… Error: Call to undefined method stdClass::language() (0) #0 /home/httpd/html/mysite.com/public_html/system/Dispatcher/External.php(64): IPS\Dispatcher\_Standard::baseJs() #1 /home/httpd/html/mysite.com/public_html/system/Dispatcher/External.php(41): IPS\Dispatcher\_External::baseJs() #2 /home/httpd/html/mysite.com/public_html/system/Dispatcher/Dispatcher.php(109): IPS\Dispatcher\_External->init() #3 /home/httpd/html/mysite.com/public_html/bouncers.php(159): IPS\_Dispatcher::i() #4 {main}  You can remove that line is it's a CLI based script. On ‎5‎/‎15‎/‎2020 at 9:14 PM, jay5r said: [To the folks who wanted my source code for parsing the emails, I'll post it when I've got things working and cleaned up.] If it's something you're willing to maintain, you could package it in an Invision Community application and list it in the Marketplace. Maxxius 1
jay5r Posted May 19, 2020 Author Posted May 19, 2020 I completed writing my routine to parse the messages in an email inbox, figure out the type of bounce, and then submit it to Mail Bouncer. I'll post the code in a few days. I want to see if I encounter any issues with it before sharing it with folks. It will not be a supported code and will come with no warranty. (Use at your own risk!) The error messages from mail hosts are just too unpredictable for me to want to deal with all the weird cases other people will encounter. Rather, think of it as a starting point for people with some knowledge of PHP programming – something you can tweak to suit your own needs, that means you don't have to start from scratch. And I should mention that it can be modified pretty easily to handle lists you may have of emails that need to be disabled. bfarber and Maxxius 1 1
stoo2000 Posted May 20, 2020 Posted May 20, 2020 On ‎5‎/‎19‎/‎2020 at 9:29 PM, jay5r said: error messages from mail hosts are just too unpredictable for me to want to deal with all the weird cases other people will encounter You hit the nail on the head there. This is the primary reason why I also do not want to get into supporting manual bounce management. The dedicated email gateways do a much better job of categorising and dealing with bounces. jay5r 1
jay5r Posted May 21, 2020 Author Posted May 21, 2020 So here's my code… It comes with a lot of caveats… Think of it as starting point so you or your developer doesn't have to start from scratch. I'm not the best PHP programmer, so my code may not be quite as beautiful as yours, but it's better than nothing. Also, this code calls MailBouncer, so you must have an active license for that. You can put the the file anywhere and name it anything (ending in .php). The code will almost certainly need to be tweaked. For example, my mail server is running SendMail. If your mail server is running something different the bulk of your messages may have different formatting. Here's what it does… Logs into your email account and scans through all the messages from postmaster@ and MAILER-DAEMON@. You can login with IMAP or POP w/ or w/o SSL. Only IMAP w/o SSL has been tested, but the code is there for the others. After processing the entire mailbox, when you repeat the process you'll probably want to do just examine the most recent period. To do that add ?days=X to the end of the URL where X is the number of days you want to examine. X can be a decimal number. When it scans it classifies things as 4 types: Indeterminate Reputation problem Hard bounce Soft bounce You won't see detailed information about hard and soft bounces, but you will if there's a reputation problem or the outcome was indeterminate. Reputation problems typically mean that your server got on a blacklist. You'll want to rectify this ASAP. Reputation problems are handled as soft bounces, since they're not the fault of the member. Indeterminate issues are when you'll probably need to tweak the code to handle the case (typically different error formatting). You can add trigger phrases to $softphrases, $hardphrases and $reputationphrases. If it's not parsing the email address that's bouncing, that's a little trickier. Or you can just manually go into the IP board admin area and do manually what Mail Bouncer does. It is possible to change up the code to not scan a mailbox and just handle a long list of emails you've manually put together – just replace everything inside if (!$mbox = imap_open($authhost, $user, $pw)){ } else {} with something that populates the $hardfails and $softfails arrays. At the end it does one other thing – it queries the database and finds everyone who has been banned for 8 weeks or longer and processes their email addresses as hard bounces. These people are probably mad at you and don't want your emails, and they're likely to mark your emails as spam just to spite you. So it's best to just treat the email as bad and if/when the member returns they can revalidate their email address. The SQL query is shown. You'll need to rewrite the actual pull from your IP.Board database. I use Fat Free Framework, so that's the syntax you'll see. To turn off handling of long bans permanently just comment out or delete the code. But you can also add lb=off to the end of the URL to not to it on a particular run of the script. With all of that said, here's the code… <?php //I USE FAT FREE FRAMEWORK, SO THERE'S AT LEAST ONE CASE WHERE YOU NEED TO REPLACE F3 CODE WITH YOUR OWN CODE $user = 'your_mail_username'; $pw = 'your_mail_pw'; $mailserver = 'localhost'; \define('REPORT_EXCEPTIONS', TRUE); $_SERVER['SCRIPT_FILENAME'] = __FILE__; require_once '/path/to/init.php'; //PATH TO THE INIT.PHP FILE FOR YOUR IP.BOARD INSTALL header('Content-Encoding: none'); ob_implicit_flush(true); ob_end_flush(); set_time_limit(60*180); echo str_repeat(' ',1024*64.1); $hardfails = array(); $softfails = array(); //THE FOLLOWING ARRAYS OF PHRASES DETERMINE THE TYPE OF FAILURE, EDIT THEM AS NEEDED $softphrases = array(); $softphrases[] = '(reason: 552'; //552 = Exceeded storage allocation $hardphrases[] = '<<< 552'; $softphrases[] = ' over quota'; $softphrases[] = ' inbox is full'; $softphrases[] = ' mailbox is full'; $softphrases[] = ' mailbox full'; $softphrases[] = 'Mail quota exceeded'; $softphrases[] = 'is over quota'; $hardphrases = array(); $hardphrases[] = '550 5.1.1'; $hardphrases[] = '550-5.1.1'; $hardphrases[] = '<<< 550'; //550 = Non-existent email address $softphrases[] = '(reason: 550'; $hardphrases[] = 'Status code: 550'; $hardphrases[] = ' mailbox unavailable'; $hardphrases[] = ' deactivated mailbox'; $hardphrases[] = ' Bad destination mailbox address'; $hardphrases[] = ' no valid recipients'; $hardphrases[] = 'Not a valid recipient'; $hardphrases[] = 'User unknown'; $hardphrases[] = ' Address does not exist'; $hardphrases[] = ' mailbox is disabled'; $hardphrases[] = ' user doesn\'t have a yahoo'; $hardphrases[] = 'is a deactivated mailbox'; $reputationphrases = array(); //things that indicate they just don't like/trust the email //this is a problem if you sent the email, not a problem if some spammer sent the email (pretending to be you) $reputationphrases[] = 'Relay access denied'; //https://serversitters.com/how-to-correct-554-5-7-1-relay-access-denied-email-errors-and-prevent-them-in-the-future.html $reputationphrases[] = ' blocked using '; //ONE OF THE FOLLOWING 4 LINES SHOULD BE UNCOMMENTED DEPENDING ON WHAT TYPE OF CONNECTION YOU WANT TO MAKE TO YOUR MAIL SERVER //$authhost="{".$mailserver.":995/pop3/ssl/novalidate-cert}"; //POP w/o SSL //$authhost="{".$mailserver.":110/pop3/notls}"; //POP w/ SSL $authhost="{".$mailserver.":993/imap/ssl/novalidate-cert}"; //IMAP w/o SSL (this is the only one that's been tested) //$authhost="{".$mailserver.":143/imap/notls}"; //IMAP w/ SSL echo '<!DOCTYPE html><html lang="en-US" dir="ltr"><head><meta charset="utf-8"></head><body>'; if (!$mbox = imap_open($authhost, $user, $pw)){ echo "<p>Could not connect to mail server.</p>"; } else { echo "<p>Connected to mail server.</p>"; $totalrows = imap_num_msg($mbox); echo "<p>Found $totalrows messages</p><ul>"; $result = imap_fetch_overview($mbox, "1:$totalrows", 0); foreach ($result as $overview) { $body = imap_fetchbody($mbox, $overview->msgno, "1"); $datetime = strtotime($overview->date); date_default_timezone_set("UTC"); if (stripos($body, 'https://web.de/email/senderguidelines') !== false && stripos($body, 'cs2172.mojohost.com') !== false) { //ignore these, problem was resolved } else if ($_GET['days'] > 0 && $datetime < time() - ($_GET['days'] * 86400)){ //do nothing, it doesn't meet the cutoff // echo "<li>Skipping: $datetime < ".(time() - ($f3->get('days') * 86400))."</li>"; } else if ((stripos($overview->from, 'Mailer-Daemon@') !== false || stripos($overview->from, 'postmaster@') !== false ) && ((strpos($body, '----- The following addresses had permanent fatal errors -----') !== false && strpos($body, '(reason: ') !== false) || (stripos($body, 'Final-Recipient: ') !== false) || (stripos($body, 'message couldn\'t be delivered to ') !== false) || (stripos($body, '> is a deactivated mailbox') !== false) || (strpos($body, ' to these recipients or groups:') !== false && strpos($body, 'The recipient\'s mailbox is full') !== false))) { //PARSE THE EMAIL ADDRESS THAT'S HAVING A PROBLEM $bademail = ''; if (strpos($body, '----- The following addresses had permanent fatal errors -----') !== false) { $pos1 = strpos($body, '----- The following addresses had permanent fatal errors -----'); $pos1 = $pos1 + strlen('----- The following addresses had permanent fatal errors -----'); $pos2 = strpos($body, '(reason: ', $pos1); if ($pos2 > 0) { $bademail = str_replace('<', '', str_replace('>', '', trim(substr($body, $pos1, $pos2 - $pos1)))); } } else if (stripos($body, 'Final-Recipient: ') !== false){ //The syntax of the field is as follows: // "Final-Recipient" ":" address-type ";" generic-address // i.e. Final-Recipient: rfc822; skijanje-zg@net.hr $pos1 = strpos($body, 'Final-Recipient: '); $pos1 = $pos1 + strlen('Final-Recipient: '); $pos2 = strpos($body, "\r", $pos1); if (strpos($body, "\n", $pos1) < $pos2){ $pos2 = strpos($body, "\n", $pos1); } if ($pos2 > 0) { $bademail = substr($body, $pos1, $pos2 - $pos1); $pos3 = strpos($bademail, ';'); if ($pos3 !== false){ $bademail = substr($bademail, $pos3 + 1); } $bademail = trim($bademail); } } else if (strpos($body, ' to these recipients or groups:') !== false && strpos($body, 'The recipient\'s mailbox is full') !== false){ $pos1 = strpos($body, ' to these recipients or groups:'); $pos1 = $pos1 + strlen(' to these recipients or groups:'); $pos2 = strpos($body, 'The recipient\'s mailbox is full', $pos1); if ($pos2 > 0) { $bademail = trim(substr($body, $pos1, $pos2 - $pos1)); if (strpos($bademail, '<') !== false && strpos($bademail, '>') !== false){ $bademail = substr($bademail, strpos($bademail, '<') + 1); $bademail = substr($bademail, 0, strpos($bademail, '>')); } } } else if(stripos($body, '> is a deactivated mailbox') !== false){ $bademail = substr($body, 0, stripos($body, '> is a deactivated mailbox')); $bademail = substr($bademail, strrpos($bademail, '<') + 1); } else if(stripos($body, 'message couldn\'t be delivered to ') !== false){ $bademail = substr($body, stripos($body, 'message couldn\'t be delivered to ') + strlen('message couldn\'t be delivered to ')); $bademail = substr($bademail, 0, strpos($bademail, '. ')); } //CLEAN UP THE EMAIL ADDRESS if (stripos($bademail, 'mailto:') === 0){ $bademail = substr($bademail, strlen('mailto:')); } if (!filter_var($bademail, FILTER_VALIDATE_EMAIL)) { echo "<li><b>ERROR: PARSED THE EMAIL $bademail BUT IT IS NOT A VALID EMAIL ADDRESS</b></li>"; $bademail = ''; } //EVALUATE DIFFERENT TYPES OF PROBLEMS $result = 'Indeterminate'; if ($result == 'Indeterminate'){ //reputation problems foreach($reputationphrases as $phrase){ if ($result == 'Indeterminate' && stripos($body, $phrase) !== false) { $result = 'Reputation Problem'; } } } if ($result == 'Indeterminate'){ //hard bounces foreach($hardphrases as $phrase){ if ($result == 'Indeterminate' && stripos($body, $phrase) !== false) { $result = 'hard'; } } } if ($result == 'Indeterminate'){ //soft bounces foreach($softphrases as $phrase){ if ($result == 'Indeterminate' && stripos($body, $phrase) !== false) { $result = 'soft'; } } } if ($result == 'Indeterminate' || $bademail == '') { echo "<li>{$overview->msgno}<ul>"; echo "<li>Sent: {$overview->date}</li><li>From: " . htmlspecialchars($overview->from) . "</li><li> Subject: {$overview->subject}</li>"; echo "<li><pre>" . htmlspecialchars(substr($body, 0, 10240)) . "</pre></li>"; echo "<li><b>Bad Email: $bademail</b></li>"; echo "<li>Date/Time: $datetime</li>"; echo "<li><b>Result: $result</b></li>"; echo "</ul></li>"; } elseif ($result == 'Reputation Problem') { echo "<li>{$overview->msgno}<ul>"; echo "<li>Sent: {$overview->date}</li><li>From: " . htmlspecialchars($overview->from) . "</li><li> Subject: {$overview->subject}</li>"; echo "<li><pre>" . htmlspecialchars(substr($body, 0, 10240)) . "</pre></li>"; echo "<li><b>Bad Email: $bademail</b></li>"; echo "<li>Date/Time: $datetime</li>"; echo "<li><b>Result: Reputation Problem (handled as a soft bounce)</b></li>"; echo "</ul></li>"; $exists = false; for($i = 0; $i < count($softfails); $i++){ list($temp_email, $temp_dt) = explode(',', $softfails[$i]); if ($temp_email == $bademail){ $exists = true; if ($temp_dt < $datetime){ $softfails[$i] = "$bademail,$datetime"; //update date time } } } if ($exists === false){ $softfails[] = "$bademail,$datetime"; } } elseif ($result == 'hard' && array_search("$bademail,$datetime", $hardfails) === false) { $exists = false; for($i = 0; $i < count($hardfails); $i++){ list($temp_email, $temp_dt) = explode(',', $hardfails[$i]); if ($temp_email == $bademail){ $exists = true; if ($temp_dt < $datetime){ $hardfails[$i] = "$bademail,$datetime"; //update date time } } } if ($exists === false){ $hardfails[] = "$bademail,$datetime"; } } elseif ($result == 'soft' && array_search("$bademail,$datetime", $softfails) === false) { $exists = false; for($i = 0; $i < count($softfails); $i++){ list($temp_email, $temp_dt) = explode(',', $softfails[$i]); if ($temp_email == $bademail){ $exists = true; if ($temp_dt < $datetime){ $softfails[$i] = "$bademail,$datetime"; //update date time } } } if ($exists === false){ $softfails[] = "$bademail,$datetime"; } } } else if (stripos($overview->subject, "Mail delivery failed") !== false) { echo "<li>{$overview->msgno}<ul>"; echo "<li>Sent: {$overview->date}</li><li>From: " . htmlspecialchars($overview->from) . "</li><li> Subject: {$overview->subject}</li>"; echo "<li><pre>" . htmlspecialchars(substr($body, 0, 10240)) . "</pre></li>"; echo "</ul></li>"; } else if (stripos($overview->subject, "Delivery Status Notification (Failure)") !== false) { //hotmale sends ones like this… echo "<li>{$overview->msgno}<ul>"; echo "<li>Sent: {$overview->date}</li><li>From: " . htmlspecialchars($overview->from) . "</li><li> Subject: {$overview->subject}</li>"; echo "<li><pre>" . htmlspecialchars(substr($body, 0, 10240)) . "</pre></li>"; echo "</ul></li>"; } else if (stripos($overview->subject, "Undeliverable: ") !== false) { //outlook sends ones like this… echo "<li>{$overview->msgno}<ul>"; echo "<li>Sent: {$overview->date}</li><li>From: " . htmlspecialchars($overview->from) . "</li><li> Subject: {$overview->subject}</li>"; echo "<li><pre>" . htmlspecialchars(substr($body, 0, 10240)) . "</pre></li>"; echo "</ul></li>"; } else if (stripos($overview->from, 'postmaster@') === 0) { //catch all echo "<li>{$overview->msgno}<ul>"; echo "<li>Sent: {$overview->date}</li><li>From: " . htmlspecialchars($overview->from) . "</li><li> Subject: {$overview->subject}</li>"; echo "<li><pre>" . htmlspecialchars(substr($body, 0, 10240)) . "</pre></li>"; echo "</ul></li>"; } else if (stripos($overview->from, 'Mailer-Daemon@') === 0) { //catch all echo "<li>{$overview->msgno}<ul>"; echo "<li>Sent: {$overview->date}</li><li>From: " . htmlspecialchars($overview->from) . "</li><li> Subject: {$overview->subject}</li>"; echo "<li><pre>" . htmlspecialchars(substr($body, 0, 10240)) . "</pre></li>"; echo "</ul></li>"; } } //end foreach echo "</ul>"; imap_close($mbox); } //connected ob_flush(); //NOW HAVE ARRAYS OF HARD AND SOFT FAILS, NEED TO PROCESS THEM… echo "<p>Please note: 'Email address not found' can mean two things – 1) that you have a problem because a member record could not be found, or 2) that the member has already corrected the problem. If you see just a few messages like that, it usually indicates that the member already corrected the problem.</p>"; echo "</ul><h2>".count($softfails)." Soft Fails</h2><ul>"; asort($softfails); foreach ($softfails as $fail){ list($email, $datetime) = explode(',', $fail); echo "<li>$email – "; ob_flush(); $member = \IPS\Member::load( $email, 'email' ); if( $member->member_id ) { $member->bouncerSoftBounce( $datetime ); echo "set as soft bounce. ($datetime)"; } else { echo "<b>EMAIL ADDRESS NOT FOUND</b>"; } echo "</li>"; ob_flush(); } echo "</ul>"; echo "<h2>".count($hardfails)." Hard Fails</h2><ul>"; asort($hardfails); foreach ($hardfails as $fail){ list($email, $datetime) = explode(',', $fail); echo "<li>$email – "; ob_flush(); $member = \IPS\Member::load( $email, 'email' ); if( $member->member_id ) { $member->bouncerHardBounce( $datetime ); echo "set as hard bounce. ($datetime)"; } else { echo "<b>EMAIL ADDRESS NOT FOUND</b>"; } echo "</li>"; } echo "</ul>"; if ($_GET['lb'] != 'off'){ $sql = "SELECT `email` FROM `core_members` WHERE `temp_ban` = -1 OR `temp_ban` > NOW() + INTERVAL 8 WEEK"; $results = $bzDB->exec($sql); //REPLACE THIS WITH A SQL QUERY TO YOUR IP.BOARD DATABASE echo "<h2>".count($results)." Long Bans (set as hard bounces)</h2><ul>"; foreach($results as $result){ $email = $result['email']; echo "<li>$email – "; ob_flush(); $member = \IPS\Member::load( $email, 'email' ); if( $member->member_id ) { $member->bouncerHardBounce( time() ); echo "set as hard bounce."; } else { echo "<b>EMAIL ADDRESS NOT FOUND</b>"; } echo "</li>"; } } echo "</body></html>"; ?>  Maxxius 1
Square Wheels Posted May 21, 2020 Posted May 21, 2020 I have no php talents at all. What I am looking for is something that will remove all email notifications and set the user to not receive notifications from the admin, and move them to a user group of my choosing. I'd even settle for a query I could run that would do all of that. I just edit the query with the email address and run it and it updates the needed tables. Right now, I am doing it manually and it takes forever, I still have over 500 to process and I am avoiding it.
Recommended Posts