Qmail/Vpopmail renaming a domain

qmailIn a Qmail/Vpopmail email server system, there is no direct way to rename a domain. Let’s say, you have a costumer that is using domain.net and then registers domain.com to replace domain.net. The obvious solution is to make domain.com an alias domain of domain.net, it’s just one simple command:

vaddaliasdomain domain.net domain.com

But if the old domain is to be dropped completely there is no logical reason to go for the domain alias route, except that is the quick and dirty solution. Also, it’s a bit stupid and confusing to be consuming all the email services (POP, IMAP, SMTP, Webmail, Control Panel) with credentials of the old domain when the domain in use is the new domain. All this hassle just because Vpopmail doesn’t provide a command do rename a domain.

Even with no direct command, it’s possible to rename a domain, keeping all the mailboxes (user@old-domain.com changes to user@new-domain.com), passwords, forwards, email alias, webmail preferences and contacts etc. It’s a bit painful, but doable:

  • move vpomail/domains/old_domain to vpomail/domains/new_domain
  • adjust if needed vpomail/domains/new_domain/.qmail-default
  • adjust if needed each mailbox .qmail file in vpomail/domains/new_domain/users(1,2,3)/.qmail
  • rename domain in rcpthosts or morercpthosts (if in morercpthosts run qmail-newmrh)
  • rename domain in qmail/users/assign and run qmail-newu
  • log in to mysql and in the vpopmail database rename the old domain table to new domain table (domain dots get converted to underscores)
  • in the new renamed table update the pw_dir field to match the new domain
  • update dir_control table to the new domain
  • update limits table
  • update valias (domain and valias_line field)
  • in the roundcube database update the users and identities tables to match the new domain in the respective old domain entries
  • restart qmail and test

If you have read all the way trough here, and are thinking in doing this procedure, WAIT i have a special treat, a script that takes care of all. It’s a PHP script, that should be executed in command line by root and accepts 2 arguments, the old domain and new domain. Just adjust the PHP path, the configurations (paths to stuff in the system), mark as executable and you are ready to go.

Beware, you will be running this as root, and i assure that it works fine on my server but i can’t assure that it won’t destroy yours. If you accept this terms please proceed and grab the script.

Continue reading “Qmail/Vpopmail renaming a domain”

35

After the Annus Horribilis i have to report that this year has gone a bit better. In what is known as the midlife crisis (yes, i even bought myself the convertible…) decisions have been made throughout the year, some tiny some big, that slowly (yet steadily) are improving my life as a whole.

  • Move out and away from a very unhappy place
  • Share new house with a friend
  • (Re)start sport activity
  • Set aside each and every person that is not correct or brings unhappiness
  • Take care and give back to each and every person that is correct and brings happiness
  • Balance work and real life
  • Enjoy what i have now, tomorrow it can be all gone

I also developed a very simple set of rules regarding relationships. Some may seem strange in the world as it is today…

  • Anyone already committed is off limits
  • Anyone in workplace is off limits
  • Don’t fool around, relationships are not a competition, less is more
  • Don’t rush nothing, it takes the time that i it takes
  • Be honest and correct (no matter what, whom or when)

And even if all things considered this as not been a good year, it has been much better than the previous one. I feel some kind of stand on point, and am crawling out of the hole, slowly but steady.

Very important goals in this year:

  • Focus, focus, focus
  • Don’t be late, don’t be late, don’t be late

Hands on the MK809II

mk809iiI bought myself a MK809II, a Chinese TV stick running Android that connects to the HDMI port of your dumb TV and transforms it in a smart TV. It’s pretty inexpensive, going for about 50 euros and pretty power efficient:

at 5V-1.5A = 7.5W maximum load * 24h = 180W/h max per day, at 0.15€ average KW/h results in a total of 0.027€ per day (around 10€/year in electric bill) if one was to use it day and night….

The specs are okay, with the RK3066 chip, dual core A9 cortex 1.6Ghz CPU and Quad core Mali 400Mhz GPU, 1GB DDR 3 RAM, 8GB internal memory (SD card expandable), WiFi b/g/n and Bluetooth 2.1. Talking about incredible bang for the buck… but as always the main question is, does it deliver?

Continue reading “Hands on the MK809II”

.qmail delivery filtering by adress and subject

My goal was simple, to filter incoming emails by subject and to address (on a catch-all address…) in the server and move the matches to a specific folder instead of the normal delivery. I’m running a Qmail+Vpopmail system, and these directions should be valid for similar setups.

Probably i could do this with Procmail or Maildrop, but it seemed all so complicated to do just a simple one time task that i opted in for the fun route, doing it myself… for a recurrent email filtering task, multiple accounts, customization, any kind of heavy email filtering i strongly suggest to stop here and go read about Procmail or Maildrop.

Still here? Good. First, add a .qmail (see dot.qmail man) in the user Maildir folder that you want to setup a filter:

| /home/vpopmail/domains/domain.com/user/filter
/usr/home/vpopmail/domains/domain/user/Maildir/

Save it and take care with the permissions, vpopmail user should be able to read it. What we are doing here is really simple, in the first line we pipe incoming emails trough filter, and according to filter exit code qmail execute (or not) the second line and proceed with the normal delivery.

Now setup the filter itself, it’s written in dirty and messy PHP but it gets the job done. Also it depends on PEAR Mail_mimeDecode, so go ahed and install it:

pear install Mail_mimeDecode

Now the filter script itself, it must be customized to your needs:

#! /usr/local/bin/php
<?php

/*
 * QMAIL FILTER EMAILS
 *
 * invoked by .qmail files
 * | /path/to/this/script
 *
 * parses email to address and subject against target strings
 * if BOTH are matched email is saved in $save_matched_dir
 * and qmail is instructed to ignore further .qmail lines
 *
 * CONFIG:
 */

$max_bytes        = 262144;            // mail size > 256Kb is not scanned
$to_address       = 'to@domain.com';   // to address filter
$subjects         = array('subject 1',
                          'match this subject',
                          'other subject');
$save_matched_dir = '/home/vpopmail/domains/domain.com/save-matched-emails/';

/*
 * QMAIL EXIT CODES
 *
 * 0 - Success (go to next .qmail line)
 * 99 - Success and abort (do not execute next lines)
 * 100 - permanent error (bounce)
 * 111 - soft error (retry later)
 */

try {
  function decodeHeader($input) {
    // Remove white space between encoded-words
    $input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?',
                         $input);

    // For each encoded-word...
    while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {

      $encoded  = $matches[1];
      $charset  = $matches[2];
      $encoding = $matches[3];
      $text     = $matches[4];
      
      switch (strtolower($encoding)) {
        case 'b':
          $text = base64_decode($text);
          break;

        case 'q':
          $text = str_replace('_', ' ', $text);
          preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
          foreach($matches[1] as $value)
            $text = str_replace('='.$value, chr(hexdec($value)), $text);
          break;
      }

      $input = str_replace($encoded, $text, $input);
    }

    if (! isset($charset))
      $charset = 'ASCII';

    $input = strtolower(
               preg_replace('/[^a-z ]/i', 
                            '', 
                 iconv($charset, 
                       'ASCII//TRANSLIT//IGNORE', 
                       $input)
               )
             );
    return $input;
  }

  $mail  = '';
  $bytes = 0;

  $fr = fopen("php://stdin", "r");
  while (!feof($fr)) {
    $mail .= fread($fr, 1024);
    $bytes += 1024;
    if ($bytes > $max_bytes) {
      fclose($fr);
      exit(0);
    }
  }
  fclose($fr);

  require_once 'Mail/mimeDecode.php';
  $decoder   = new Mail_mimeDecode($mail);
  $structure = $decoder->decode(array('decode_headers' => true));

  // check from address
  $patt = '/[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\.-][a-z0-9]+)*)+\\.[a-z]{2,}/i';
  preg_match($patt, 
             $structure->headers['to'], $matches);
  if (isset($matches[0]) && $matches[0] == $to_address) {
    // check subject
    $structure->headers['subject'] = decodeHeader($structure->headers['subject']);

    foreach ($subjects as $subject) {
       if (strpos($structure->headers['subject'], $subject) !== false) {
         $fw = fopen($save_matched_dir.
                     time().
                     '.'.
                     rand(1000, 99999).
                     '.'.
                     gethostname().
                     'S='.
                     strlen($mail).
                     ':2', 'w');
         fwrite($fw, $mail);
         fclose($fw);
         exit(99);
         // exit(0);
       }
    }
  }
} catch (Exception $e) {
}


// default, continue normal processing
exit(0);

?>

save, add the php hash bang, mark it executable and vpopmail owned. Also, the $save_matched_dir is not created and should already be present in your system.

Thats it. After this setup you should start seeing a steady flow of matched emails being saved in the matched directory and not delivered in your Inbox. As usually this works like a charm to me but can work incredible bad for you, so use at your own peril.

(auto magically) Deleting old Spam emails

If you followed My Qmail installation guide, or are using some kind of webmail or IMAP client that puts “SPAM” marked emails in some special folder, you can provide auto delete of old spam emails.

The popular Roundcube webmail has the movespam plugin (actually it’s broken, but is an easy fix) that moves spam to …/user/Maildir/.Junk folder. And this makes very easy to have a cron invoked script that deletes old spam emails.

So (in PHP), and with a threshold of 30 days (older are deleted):

$threshold = time() - (60*60*24*30); // 30 days

$junk_folders = shell_exec('find /home/vpopmail/domains/ -name .Junk -type d');
$junk_folders = explode("\n", $junk_folders);
$junk_folders = array_filter($junk_folders);

foreach ($junk_folders as $junk_folder) {
  foreach (array('new','cur') as $subfolder) {
    $d = dir($junk_folder.'/'.$subfolder);
    while (false !== ($entry = $d->read())) {
      if ($entry != '.' && $entry != '..' && is_file($d->path.'/'.$entry)) {
        if (filemtime($d->path.'/'.$entry) < $threshold)
          unlink($d->path.'/'.$entry);
      }
    }
  }
}

When we are deleting emails directly like this, you are screwing the user quota so probably it’s not a bad idea to rebuild quotas after running the old spam delete script.