A radically different approach would be to introduce a new 'expired' queue and move messages there when they need to be expired, and to introduce a new postqueue flag to flush the expired queue (the queue manager should not normally scan the expired queue because that would slow down all deliveries).
Pro: Less complexity. No 'expired' state inside queue files. Con: More complexity. When expired mail needs to be deferred because the bounce daemon is failing, it should go back to the expired queue, not to the deferred queue. Wietse