<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://kb.rvmgroup.it/index.php?action=history&amp;feed=atom&amp;title=Convertire_Cartelle_Locali_di_Thunderbird_in_Maildir</id>
	<title>Convertire Cartelle Locali di Thunderbird in Maildir - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://kb.rvmgroup.it/index.php?action=history&amp;feed=atom&amp;title=Convertire_Cartelle_Locali_di_Thunderbird_in_Maildir"/>
	<link rel="alternate" type="text/html" href="https://kb.rvmgroup.it/index.php?title=Convertire_Cartelle_Locali_di_Thunderbird_in_Maildir&amp;action=history"/>
	<updated>2026-05-05T14:53:20Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.2</generator>
	<entry>
		<id>https://kb.rvmgroup.it/index.php?title=Convertire_Cartelle_Locali_di_Thunderbird_in_Maildir&amp;diff=9857&amp;oldid=prev</id>
		<title>Gabriele.vivinetto: Created page with &quot;* Questa operazione consente di convertire una gerarchia di cartelle messaggi da Thunderbird direttamente in formato Maildir, trasportabile direttamente su un server IMAP  * Q...&quot;</title>
		<link rel="alternate" type="text/html" href="https://kb.rvmgroup.it/index.php?title=Convertire_Cartelle_Locali_di_Thunderbird_in_Maildir&amp;diff=9857&amp;oldid=prev"/>
		<updated>2016-09-21T14:55:48Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;* Questa operazione consente di convertire una gerarchia di cartelle messaggi da Thunderbird direttamente in formato Maildir, trasportabile direttamente su un server IMAP  * Q...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;* Questa operazione consente di convertire una gerarchia di cartelle messaggi da Thunderbird direttamente in formato Maildir, trasportabile direttamente su un server IMAP&lt;br /&gt;
&lt;br /&gt;
* Questa operazione è possibile anche con cartelli Imap scaricate in Thunderbird Offline&lt;br /&gt;
&lt;br /&gt;
* Avendo a disposizione il file MBOX di thunderbird, usare [http://perfectmaildir.home-dn.net/perfect_maildir/perfect_maildir.pl questo script]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/perl -w&lt;br /&gt;
&lt;br /&gt;
# &amp;quot;Simple but Perfect&amp;quot; mbox to Maildir converter v0.3&lt;br /&gt;
# Copyright (C) 2001-2003  Philip Mak &amp;lt;pmak@aaanime.net&amp;gt;&lt;br /&gt;
# &lt;br /&gt;
# This program is free software; you can redistribute it and/or&lt;br /&gt;
# modify it under the terms of the GNU General Public License&lt;br /&gt;
# as published by the Free Software Foundation; either version 2&lt;br /&gt;
# of the License, or (at your option) any later version.&lt;br /&gt;
# &lt;br /&gt;
# This program is distributed in the hope that it will be useful,&lt;br /&gt;
# but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
# GNU General Public License for more details.&lt;br /&gt;
# &lt;br /&gt;
# You should have received a copy of the GNU General Public License&lt;br /&gt;
# along with this program; if not, write to the Free Software&lt;br /&gt;
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
use strict;&lt;br /&gt;
use Date::Parse qw( str2time );&lt;br /&gt;
&lt;br /&gt;
#### Settings&lt;br /&gt;
# This will be used to set the file time (needed for courier-imap and some others)&lt;br /&gt;
# $datestyle = &amp;quot;date&amp;quot;: extract date from the &amp;quot;Date: &amp;quot; header&lt;br /&gt;
# $datestyle = &amp;quot;from&amp;quot;: extract date from the &amp;quot;From &amp;quot; mbox header&lt;br /&gt;
my $datestyle = &amp;quot;from&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Use maildir++ format (append the message size to the filename)&lt;br /&gt;
my $maildirplus = 0;&lt;br /&gt;
####&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Get the hostname&lt;br /&gt;
my $hostname = `hostname`;&lt;br /&gt;
chomp ($hostname);&lt;br /&gt;
&lt;br /&gt;
# check for valid arguments&lt;br /&gt;
my ($maildir) = @ARGV;&lt;br /&gt;
if (!$maildir) {&lt;br /&gt;
  print STDERR &amp;quot;Usage: perfect_maildir ~/Maildir &amp;lt; mbox\n&amp;quot;;&lt;br /&gt;
  exit 1;&lt;br /&gt;
} elsif (! -d $maildir) {&lt;br /&gt;
  print STDERR &amp;quot;Cannot open $maildir\n&amp;quot;;&lt;br /&gt;
  exit 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# check for writable maildir&lt;br /&gt;
unless (-w &amp;quot;$maildir/cur&amp;quot;) {&lt;br /&gt;
  print STDERR &amp;quot;Cannot write to $maildir/cur\n&amp;quot;;&lt;br /&gt;
  exit 1;&lt;br /&gt;
}&lt;br /&gt;
unless (-w &amp;quot;$maildir/new&amp;quot;) {&lt;br /&gt;
  print STDERR &amp;quot;Cannot write to $maildir/new\n&amp;quot;;&lt;br /&gt;
  exit 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
my $num = 0;&lt;br /&gt;
my $time = time;&lt;br /&gt;
my $date;&lt;br /&gt;
my $delivered_time;&lt;br /&gt;
&lt;br /&gt;
repeat:&lt;br /&gt;
&lt;br /&gt;
# read header&lt;br /&gt;
my $headers = &amp;#039;&amp;#039;;&lt;br /&gt;
my $flags = &amp;#039;&amp;#039;;&lt;br /&gt;
my $subject = &amp;#039;&amp;#039;;&lt;br /&gt;
while (my $line = &amp;lt;STDIN&amp;gt;) {&lt;br /&gt;
  # detect end of headers&lt;br /&gt;
  last if $line eq &amp;quot;\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if ($datestyle eq &amp;quot;from&amp;quot;) {&lt;br /&gt;
    # Get date from the &amp;quot;From &amp;quot; line (this should appears here for the first message only)&lt;br /&gt;
    $date = $1 if $line =~ /^From [^ ^\t]+[ \t]+(.{24})/;&lt;br /&gt;
  } elsif ($datestyle eq &amp;quot;date&amp;quot;) {&lt;br /&gt;
    # Get date from the &amp;quot;Date: &amp;quot; header&lt;br /&gt;
    $date = $1 if $line =~ /^Date: (.*)$/;&lt;br /&gt;
  }&lt;br /&gt;
  # strip &amp;quot;From&amp;quot; line from header&lt;br /&gt;
  $headers .= $line unless $line =~ /^From ./;&lt;br /&gt;
&lt;br /&gt;
  # detect flags&lt;br /&gt;
  $flags .= $1 if $line =~ /^Status: ([A-Z]+)/;&lt;br /&gt;
  $flags .= $1 if $line =~ /^X-Status: ([A-Z]+)/;&lt;br /&gt;
  $subject = $1 if $line =~ /^Subject: (.*)$/;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$num++;&lt;br /&gt;
&lt;br /&gt;
if ($datestyle =~ /(from|date)/) {&lt;br /&gt;
  $delivered_time = str2time(&amp;quot;$date&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
  $delivered_time = $time;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# open output file&lt;br /&gt;
my $file;&lt;br /&gt;
if ($flags =~ /O/) {&lt;br /&gt;
  $file = sprintf( &amp;quot;%s%05d%s&amp;quot;, &amp;quot;$maildir/cur/$delivered_time.&amp;quot;, $num, &amp;quot;.$hostname&amp;quot; );&lt;br /&gt;
  my $extra = &amp;#039;&amp;#039;;&lt;br /&gt;
  $extra .= &amp;#039;F&amp;#039; if $flags =~ /F/; # flagged&lt;br /&gt;
  $extra .= &amp;#039;R&amp;#039; if $flags =~ /A/; # replied&lt;br /&gt;
  $extra .= &amp;#039;S&amp;#039; if (($flags =~ /R/) || ($flags =~ /O/)); # seen&lt;br /&gt;
  $extra .= &amp;#039;T&amp;#039; if $flags =~ /D/; # trashed&lt;br /&gt;
  $file .= &amp;quot;:2,$extra&amp;quot; if $extra;&lt;br /&gt;
} else {&lt;br /&gt;
  $file = sprintf( &amp;quot;%s%05d%s&amp;quot;, &amp;quot;$maildir/new/$delivered_time.&amp;quot;, $num, &amp;quot;.$hostname&amp;quot; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# filter out the &amp;quot;DON&amp;#039;T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA&amp;quot; message or the message doesn&amp;#039;t exists&lt;br /&gt;
if (($num == 1 and $subject eq &amp;quot;DON&amp;#039;T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA&amp;quot;) || (!$headers)) {&lt;br /&gt;
	$file = &amp;#039;/dev/null&amp;#039;;&lt;br /&gt;
	$num--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
open(FILE, &amp;quot;&amp;gt;$file&amp;quot;);&lt;br /&gt;
print FILE &amp;quot;$headers\n&amp;quot;;&lt;br /&gt;
while (my $line = &amp;lt;STDIN&amp;gt;) {&lt;br /&gt;
  if ($datestyle eq &amp;quot;from&amp;quot;) {&lt;br /&gt;
    # Get date from the &amp;quot;From &amp;quot; line (this should appears here for the first message only)&lt;br /&gt;
    $date = $1 if $line =~ /^From [^ ^\t]+[ \t]+(.{24})/;&lt;br /&gt;
  }&lt;br /&gt;
    # End of current message &lt;br /&gt;
  last if ($line =~ /^From ./);&lt;br /&gt;
&lt;br /&gt;
  # unescape &amp;quot;From&amp;quot;&lt;br /&gt;
  $line =~ s/^&amp;gt;From (.)/From $1/;&lt;br /&gt;
&lt;br /&gt;
  print FILE $line;&lt;br /&gt;
}&lt;br /&gt;
close(FILE);&lt;br /&gt;
&lt;br /&gt;
utime( $time, $delivered_time, $file ) if ($datestyle =~ /(from|date)/);&lt;br /&gt;
&lt;br /&gt;
if ($maildirplus) {&lt;br /&gt;
	my $size = -s $file;&lt;br /&gt;
	my $mdplusfile = $file;&lt;br /&gt;
	$mdplusfile =~ s/\.$hostname/.$hostname,S=$size/;&lt;br /&gt;
	rename $file,$mdplusfile;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
goto repeat unless eof(STDIN);&lt;br /&gt;
&lt;br /&gt;
my $elapsed = time - $time;&lt;br /&gt;
print &amp;quot;Inserted $num messages into maildir $maildir in $elapsed seconds\n&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Creare una maildir vuota con&lt;br /&gt;
 maildirmake ./cartella&lt;br /&gt;
&lt;br /&gt;
* Convertire il file MBOX con&lt;br /&gt;
 ./perfect_maildir.pl ./cartella &amp;lt; FILEMBOX&lt;br /&gt;
&lt;br /&gt;
* Nei riferimenti lo script per convertire un&amp;#039;intera gerarchia di cartelle&lt;br /&gt;
&lt;br /&gt;
=Riferimenti=&lt;br /&gt;
*[https://blogs.gnome.org/muelli/2012/11/converting-mailman-archives-mboxes-to-maildir/ Converting Mailman archives (mboxes) to maildir – muellis blog]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
= Converting Mailman archives (mboxes) to maildir =&lt;br /&gt;
   &lt;br /&gt;
I wanted to search discussions on mailing lists and view conversations. I didn&amp;amp;#8217;t want to use some webinterface because that wouldn&amp;amp;#8217;t allow me to search quickly and offline. So making my mail client aware of these emails seemed to be the way to go. Fortunately, the GNOME mailinglists are mbox archived. So you download the entire traffic in a [[standardised mbox]].&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
But how to properly get this into your email clients then? I think Thunderbird can import mbox natively. But I wanted to access it from other clients, too, so I needed to make my server aware of these emails. Of course, I configured my mailserver to use [[maildir]], so some conversion was needed.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
I will present my experiences dealing with this problem. If you want to do similar things, or even only want to import the mbox directly, this post might be for you.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
=== The archives ===&lt;br /&gt;
 &lt;br /&gt;
First, we need to get all the archives. As I had to deal with a couple of mailinglists and more than a couple of month, I couldn&amp;amp;#8217;t be arsed to click every single mbox file manually.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
The following script scrapes the mailman page. It makes use of the interesting [[Splinter library]], basically a wrapper around selenium and other browsers for Python.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&lt;br /&gt;
import getpass&lt;br /&gt;
from subprocess import Popen, list2cmdline&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
import splinter&lt;br /&gt;
&lt;br /&gt;
def fill_password(b, username=None, password=None):&lt;br /&gt;
    if not username:&lt;br /&gt;
        username = getpass.getpass(&amp;#039;username: &amp;#039;)&lt;br /&gt;
    if not password:&lt;br /&gt;
        password = getpass.getpass(&amp;#039;password: &amp;#039;)&lt;br /&gt;
        &lt;br /&gt;
    b.fill(&amp;#039;username&amp;#039;, username)&lt;br /&gt;
    b.fill(&amp;#039;password&amp;#039;, password)&lt;br /&gt;
    b.find_by_name(&amp;#039;submit&amp;#039;).click()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main(url, username=None):&lt;br /&gt;
    b = splinter.Browser()&lt;br /&gt;
    &lt;br /&gt;
    try:&lt;br /&gt;
        #url = &amp;#039;https://mail.gnome.org/mailman/private/board-list/&amp;#039;&lt;br /&gt;
        b.visit(url)&lt;br /&gt;
        &lt;br /&gt;
        if &amp;#039;Password&amp;#039; in b.html:&lt;br /&gt;
            fill_password(b, username=username)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        links = [l[&amp;#039;href&amp;#039;] for l in b.find_link_by_partial_text(&amp;#039;Text&amp;#039;)]&lt;br /&gt;
&lt;br /&gt;
        cookie = b.driver.get_cookies()[0]&lt;br /&gt;
        cookie_name = cookie[&amp;#039;name&amp;#039;]&lt;br /&gt;
        cookie_value = cookie[&amp;#039;value&amp;#039;]&lt;br /&gt;
        cookie_str = &amp;quot;Cookie: {name}={value}&amp;quot;.format(name=cookie_name, value=cookie_value)&lt;br /&gt;
        wget_cookie_arg = &amp;#039;--header={0}&amp;#039;.format(cookie_str)&lt;br /&gt;
        #print  wget_cookie_arg&lt;br /&gt;
        &lt;br /&gt;
        b.quit()&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
        for link in links:&lt;br /&gt;
            #print link&lt;br /&gt;
            cmd = [&amp;#039;wget&amp;#039;, wget_cookie_arg, link]&lt;br /&gt;
            print list2cmdline(cmd)&lt;br /&gt;
            # pipe that to &amp;quot;parallel -j 8&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    except:&lt;br /&gt;
        b.quit()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;#039;__main__&amp;#039;:&lt;br /&gt;
    site = sys.argv[1]&lt;br /&gt;
    user = sys.argv[2]&lt;br /&gt;
    &lt;br /&gt;
    if site.startswith(&amp;#039;http&amp;#039;):&lt;br /&gt;
        url=site&lt;br /&gt;
    else:&lt;br /&gt;
        url = &amp;#039;https://mail.gnome.org/mailman/private/{0}&amp;#039;.format(site)&lt;br /&gt;
    &lt;br /&gt;
    main(username=user, url=url)&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
You can [[download the thing, too]].&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
I use splinter because handling cookies is not fun as well as parsing the web page. So I just use whatever is most convenient for me, I wanted to get things done, after all. The script will print a line for each link it found, nicely prefixed with &amp;lt;code&amp;gt;wget&amp;lt;/code&amp;gt; and its necessary arguments for the authorization cookie. You can pipe that to &amp;lt;code&amp;gt;sh&amp;lt;/code&amp;gt; but if you want to download many month, you want to do it in parallel. And fortunately, [[there is an app for that]]!&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
=== Conversion to maildir ===&lt;br /&gt;
 &lt;br /&gt;
After having received the mboxes, it turned out to be a good idea nonetheless to convert to maildir; if only to extract properly formatted mails only and remove duplicates.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
I came around [[mb2md-3.20.pl from 2004]] quite soon, but it is broken. It cannot parse the mboxes I have properly. It will create broken mails with header lingering around as it seems to be unable to detect the beginning of new mails reliably. It took me a good while to find the problem though. So again, be advised, [[do not use mb2md 3.20]].&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
As I use mutt myself I found [[this blog article]] promising. It uses mutt to create a mbox out of a maildir. I wanted it the other way round, so after a few trial and errors, I figured that the following would do what I wanted:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mutt -f mymbox -e &amp;#039;set mbox_type=maildir; set confirmcreate=no; set delete=no; push &amp;quot;T.*;s/tmp/mymuttmaildir&amp;quot;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
where &amp;amp;#8220;&amp;lt;code&amp;gt;mymbox&amp;lt;/code&amp;gt;&amp;amp;#8221; is your source file and &amp;amp;#8220;&amp;lt;code&amp;gt;/tmp/mymuttmaildir&amp;lt;/code&amp;gt;&amp;amp;#8221; the target directory.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
This is a bit lame right? We want to have parameters, because we want to do some batch processing on many archive mboxes.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
The problem is, though, that the parameters are very deep inside the quotes. So just doing something like&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mutt -f $source -e &amp;#039;set mbox_type=maildir; set confirmcreate=no; set delete=no; push &amp;quot;T.*;s$target&amp;quot;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
wouldn&amp;amp;#8217;t work, because the $target would be interpreted as a raw string due to the single quotes. And I couldn&amp;amp;#8217;t find a way to make it work so I decided to make it work with the language that I like the most: Python. So an hour or so later I came up with the following which works (kinda):&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import os&lt;br /&gt;
import subprocess&lt;br /&gt;
source = os.environ[&amp;#039;source&amp;#039;]&lt;br /&gt;
destination = os.environ[&amp;#039;destination&amp;#039;]&lt;br /&gt;
&lt;br /&gt;
conf = &amp;#039;set mbox_type=maildir; set confirmcreate=no; set delete=no; push &amp;quot;T.*;s{0}&amp;quot;&amp;#039;.format(destination)&lt;br /&gt;
&lt;br /&gt;
cmd = [&amp;#039;mutt&amp;#039;, &amp;#039;-f&amp;#039;, source, &amp;#039;-e&amp;#039;, conf]&lt;br /&gt;
subprocess.call(cmd)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
But well, I shouldn&amp;amp;#8217;t become productive just yet by doing real work. Mutt apparently expects a terminal. It would just prompt me with &amp;amp;#8220;No recipients were specified.&amp;amp;#8221;.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
So alright, this unfortunately wasn&amp;amp;#8217;t what I wanted. I you don&amp;amp;#8217;t need batch processing though, you might very well go with mutt doing your mbox to maildir conversion (or vice versa).&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Damnit, another two hours or more wasted on that. I was at the point of just doing the conversion myself. Shouldn&amp;amp;#8217;t be too hard after all, right? While researching I found that Python&amp;amp;#8217;s stdlib has some email related functions *yay*. [[Some dude on the web]] wrote something close to what I needed. I beefed it up a very little bit and landed with the following:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&lt;br /&gt;
# http://www.hackvalue.nl/en/article/109/migrating%20from%20mbox%20to%20maildir&lt;br /&gt;
&lt;br /&gt;
import datetime&lt;br /&gt;
import email&lt;br /&gt;
import email.Errors&lt;br /&gt;
import mailbox&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def msgfactory(fp):&lt;br /&gt;
    try:&lt;br /&gt;
        return email.message_from_file(fp)&lt;br /&gt;
    except email.Errors.MessageParseError:&lt;br /&gt;
        # Don&amp;#039;t return None since that will&lt;br /&gt;
        # stop the mailbox iterator&lt;br /&gt;
        return &amp;#039;&amp;#039;&lt;br /&gt;
dirname = sys.argv[1]&lt;br /&gt;
inbox = sys.argv[2]&lt;br /&gt;
fp = open(inbox, &amp;#039;rb&amp;#039;)&lt;br /&gt;
mbox = mailbox.UnixMailbox(fp, msgfactory)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
        storedir = os.mkdir(dirname, 0750)&lt;br /&gt;
        os.mkdir(dirname + &amp;quot;/new&amp;quot;, 0750)&lt;br /&gt;
        os.mkdir(dirname + &amp;quot;/cur&amp;quot;, 0750)&lt;br /&gt;
except:&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
count = 0&lt;br /&gt;
for mail in mbox:&lt;br /&gt;
        count+=1&lt;br /&gt;
        #hammertime = time.time() # mail.get(&amp;#039;Date&amp;#039;, time.time())&lt;br /&gt;
        hammertime = datetime.datetime(*email.utils.parsedate(mail.get(&amp;#039;Date&amp;#039;,&amp;#039;&amp;#039;))[:7]).strftime(&amp;#039;%s&amp;#039;)&lt;br /&gt;
        hostname = &amp;#039;mb2mdpy&amp;#039;&lt;br /&gt;
        filename = dirname + &amp;quot;/cur/%s%d.%s:2,S&amp;quot; % (hammertime, count, hostname)&lt;br /&gt;
        mail_file = open(filename, &amp;#039;w+&amp;#039;)&lt;br /&gt;
        mail_file.write(mail.as_string())&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;Processed {0} mails&amp;quot;.format(count)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
And it seemed to work well! It recovered many more emails than the Perl script (hehe) but the generated maildir wouldn&amp;amp;#8217;t work with my IMAP server. I was confused. The mutt maildirs worked like charm and I couldn&amp;amp;#8217;t see any difference to mine.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
I &amp;lt;code&amp;gt;scp&amp;lt;/code&amp;gt;ed the file onto my &amp;lt;code&amp;gt;.maildir/&amp;lt;/code&amp;gt; on my server, which takes quite a while because &amp;lt;code&amp;gt;scp&amp;lt;/code&amp;gt; isn&amp;amp;#8217;t all too quick when it comes to many small files. Anyway, it wouldn&amp;amp;#8217;t necessarily work for some reason which is way beyond me. Eventually I &amp;lt;code&amp;gt;straced&amp;lt;/code&amp;gt; the IMAP server and figured that it was desperately looking for a &amp;lt;code&amp;gt;tmp/&amp;lt;/code&amp;gt; folder. Funnily enough, it didn&amp;amp;#8217;t need that for other maildirs to work. Anyway: Lesson learnt: If your &amp;lt;code&amp;gt;[[dovecot]]&amp;lt;/code&amp;gt; doesn&amp;amp;#8217;t play well with your maildir and you have no clue how to make it log more verbosely, check whether you need a &amp;lt;code&amp;gt;tmp/&amp;lt;/code&amp;gt; folder.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
But I didn&amp;amp;#8217;t know that so I investigated a bit more and I found [[another PERL script]] which converted the emails fine, too. For some reason it put my mails in &amp;amp;#8220;&amp;lt;code&amp;gt;.new/&amp;lt;/code&amp;gt;&amp;amp;#8221; and not in &amp;amp;#8220;&amp;lt;code&amp;gt;.cur/&amp;lt;/code&amp;gt;&amp;amp;#8220;, which the other tools did so far. Also, it would leave the messages as unread which I don&amp;amp;#8217;t like.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Fortunately, one (more or less) only needs to rename the files in a maildir to end in &amp;lt;code&amp;gt;S&amp;lt;/code&amp;gt; for &amp;amp;#8220;seen&amp;amp;#8221;. While this sounds like a simple&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for f in maildir/cur/*; do mv ${f} ${f}:2,S&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
it&amp;amp;#8217;s not so easy anymore when you have to move the directory as well. But that&amp;amp;#8217;s easily being worked around by shuffling the directories around.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Another, more annoying problem with that is &amp;amp;#8220;[[Argument list too long]]&amp;amp;#8221; when you are dealing with a lot of files. So a solution must involve &amp;amp;#8220;&amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt;&amp;amp;#8221; and might look something like this: &amp;lt;code&amp;gt;find ${CUR} -type f -print0 | xargs -i -0 mv &amp;#039;{}&amp;#039; &amp;#039;{}&amp;#039;:2,S&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
=== Duplicates ===&lt;br /&gt;
 &lt;br /&gt;
There was, however, a very annoying issue left: Duplicates. I haven&amp;amp;#8217;t investigated where the duplicates came from but it didn&amp;amp;#8217;t matter to me as I didn&amp;amp;#8217;t want duplicates even if the downloaded mbox archive contained them. And in my case, I&amp;amp;#8217;m quite confident that the mboxes are messed up. So I wanted to get rid of duplicates anyway and decided to use a hash function on the file content to determine whether two file are the same or not. I used &amp;lt;code&amp;gt;sha1sum&amp;lt;/code&amp;gt; like this:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ find maildir/.board-list/ -type f -print0 | xargs -0 sha1sum   | head&lt;br /&gt;
c6967e7572319f3d37fb035d5a4a16d56f680c59  maildir/.board-list/cur/1342797208.000031.mbox:2,&lt;br /&gt;
2ea005ec0e7676093e2f488c9f8e5388582ee7fb  maildir/.board-list/cur/1342797281.000242.mbox:2,&lt;br /&gt;
a4dc289a8e3ebdc6717d8b1aeb88959cb2959ece  maildir/.board-list/cur/1342797215.000265.mbox:2,&lt;br /&gt;
39bf0ebd3fd8f5658af2857f3c11b727e54e790a  maildir/.board-list/cur/1342797210.000296.mbox:2,&lt;br /&gt;
eea1965032cf95e47eba37561f66de97b9f99592  maildir/.board-list/cur/1342797281.000114.mbox:2,&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
and if there were two files with the same hash, I would delete one of them. Probably like so:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    #!/usr/bin/env python&lt;br /&gt;
    import os&lt;br /&gt;
    import sys&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    hashes = []&lt;br /&gt;
    for line in sys.stdin.readlines():&lt;br /&gt;
        hash, fname = line.split()&lt;br /&gt;
        if hash in hashes:&lt;br /&gt;
            os.unlink(fname)&lt;br /&gt;
        else:&lt;br /&gt;
            hashes.append(hash)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
But it turns out that the following snippet works, too:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
find /tmp/maildir/ -type f -print0 | xargs -0 sha1sum | sort | uniq -d -w 40 | awk &amp;#039;{print $2}&amp;#039; | xargs rm&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
So it&amp;amp;#8217;ll check the files for the same contents via a . In order to make &amp;lt;code&amp;gt;uniq&amp;lt;/code&amp;gt; detect equal lines, we need to give it sorted input. Hence the &amp;lt;code&amp;gt;sort&amp;lt;/code&amp;gt;. We cannot, however, check the whole lines for equality as the filename will show up in the line and it will of course be different. So we only compare the size of the hex representation of the hash, in this case 40 bytes. If we found such a duplicate hash, we cut off the hash, take the filename, which is the remainder of the line, and delete the file.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Phew. What a trip so far. Let&amp;amp;#8217;s put it all together:&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
=== The final thing ===&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LIST=board-list&lt;br /&gt;
&lt;br /&gt;
umask 077&lt;br /&gt;
&lt;br /&gt;
DESTBASE=/tmp/perfectmdir&lt;br /&gt;
&lt;br /&gt;
LISTBASE=${DESTBASE}/.${LIST}&lt;br /&gt;
&lt;br /&gt;
CUR=${LISTBASE}/cur&lt;br /&gt;
NEW=${LISTBASE}/new&lt;br /&gt;
TMP=${LISTBASE}/tmp&lt;br /&gt;
&lt;br /&gt;
mkdir -p ${CUR}&lt;br /&gt;
mkdir -p ${NEW}&lt;br /&gt;
mkdir -p ${TMP}&lt;br /&gt;
&lt;br /&gt;
for f in  /tmp/${LIST}/*; do /tmp/perfect_maildir.pl ${LISTBASE} &amp;amp;lt; ${f} ; done&lt;br /&gt;
mv ${CUR} ${CUR}.tmp&lt;br /&gt;
mv ${NEW} ${CUR}&lt;br /&gt;
mv ${CUR}.tmp ${NEW}&lt;br /&gt;
find ${CUR} -type f -print0 | xargs -i -0 mv &amp;amp;#039;{}&amp;amp;#039;  &amp;amp;#039;{}&amp;amp;#039;:2,S&lt;br /&gt;
find ${CUR} -type f -print0 | xargs -0 sha1sum | sort | uniq -d -w 40 | awk &amp;amp;#039;{print $2}&amp;amp;#039; | xargs rm&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
And that&amp;amp;#8217;s handling email in 2012&amp;amp;#8230;&lt;br /&gt;
&lt;br /&gt;
=Riferimenti=&lt;/div&gt;</summary>
		<author><name>Gabriele.vivinetto</name></author>
	</entry>
</feed>