Actually if you let mail sit 30 days with items or if it's COD and past 3 days the mail returns to players seemingly empty because the mail_items table never changes the receiver back to the original sender. I've had to manually fix this in the database many time until I added this fix:
//mail will be returned:
CharacterDatabase.PExecute("UPDATE mail SET sender = '%u', receiver = '%u', expire_time = '" UI64FMTD "', deliver_time = '" UI64FMTD "',cod = '0', checked = '%u' WHERE id = '%u'", m->receiver, m->sender, (uint64)(basetime + 30*DAY), (uint64)basetime, MAIL_CHECK_MASK_RETURNED, m->messageID);
+ CharacterDatabase.PExecute("UPDATE mail_items SET receiver = '%u' where mail_id = '%u'", m->sender, m->messageID);
delete m;
continue;
}