Mail forwarding blocked by SPF

Some time ago I moved away from Yahoo mail to my own hosted address, and used the forwarding function to pass through any residual mail. This worked fine for several years, but now my host has implemented strict SPF control and a lot of the forwarded mails get rejected.

Unfortunately Yahoo doesn’t give any sophisticated options to handle this, eg. there are a number of options they could have implemented for forwarding from the Yahoo address without looking like it’s spam:

  • normal forwarding, or as an attachment
  • putting the sender in the Reply-To header
  • or even a line of text saying who the original sender was

The only way I found to get around this was to stop the forwarding, and use a PHP script to periodically check my Yahoo account via POP and move the mail to my new IMAP account. This actually works fine, so in case it’s of use to others here is the script I use:

<html><body><pre>
<?php 

docopy("{pop.mail.yahoo.com:995/pop3/ssl}INBOX","Yahoo email","Yahoo password",
       "{Target imap:143}INBOX", "Target login", "Target password");

function docopy($smailbox, $suser, $spwd, $tmailbox, $tuser, $tpwd) {
  echo "--------------------\nCopying mail from $smailbox:$suser to $tmailbox:$tuser\n--------------------\n";

  if (!($source = imap_open($smailbox, $suser, $spwd))) {
    echo "Connect to source failed";
    exit(1);
  }

  echo "Connected source: $source\n";

  $msgcount = imap_num_msg($source);

  if ($msgcount == 0) {
    echo "No messages to process\n\n";
    imap_close($source);
    return;
  }

  echo "Messages: $msgcount\n";

  if (!($target = imap_open($tmailbox, $tuser, $tpwd))) {
    echo "Connect to target failed";
    imap_close($source);
    exit(1);
  }

  echo "Connected target: $target\n";

  for ($msg = 1; $msg <= $msgcount; $msg++) {
    echo "\nProcessing message $msg\n";

    $header = imap_fetchheader($source, $msg);
    $body = imap_body($source, $msg);

    if (!imap_append($target, $tmailbox, $header . $body)) {
      echo "Saving message failed";
      imap_close($source);
      imap_close($target);
      exit(1);
    }

    echo "Message saved\n";

    if (!imap_delete($source, $msg)) {
      echo "Deleting message failed";
      imap_close($source);
      imap_close($target);
      exit(1);
    }

    echo "Message deleted\n";
  }

  imap_expunge($source);

  imap_close($source);
  imap_close($target);

  echo "Completed copy\n\n";
}
?>
</pre></body></html>

Obviously you have to fill in the bits for Yahoo email, Yahoo password, Target imap etc. It should also work for other POP or IMAP sources/targets, but I haven’t tried it.

The function can be called several times if you have more than one account to copy, in my case two works fine.

It’s written to give some level of output if you run it through a web server, then once it’s working you can schedule it to run every few minutes via cron or similar.

Leave a Reply

Your email address will not be published. Required fields are marked *