You probably need to supply some arguments to formail -- perhaps some of -Yeds -- to help it figure out where your messages start and stop. However, formail can't promise to get it 100% right, so you'll end up with mutilated and merged messages.
If you were as paranoid as I am, you would run each message through formail and concatenate the output into a single file; that file would be a valid mbox. This will take a long time for many messages; but if you are running this regularly it should be tolerable.
# Untested
foreach my $flavor qw( SPAM HAM ) {
my $file = "/home/mail/mbox/${flavor}.mbox";
$imap->select($flavor);
my @msgs = $imap->search("ALL");
foreach my $msg (@msgs) {
open my $pipe, "| formail >> $file" or die "$!";
$imap->message_to_file($pipe, $msg);
close $pipe or die "$!";
$imap->delete_message($msg);
}
}