The existing on_hold, hold_date and reset_date fields of the civicrm_email table should be put to good use as follows:
There should be a checkbox next to every email address field that would put the email address "On Hold" (or take it off hold).
Manually putting an email address on hold should set civicrm_email.on_hold = true, and civicrm_email.hold_date to the current date.
Manually taking an email address off hold should set civicrm_email.on_hold = false, and the reset_date to the current date.
If an email address is on hold, the contact summary view should state that it's On Hold in red next to the email address itself.
Contact Selector (search results and manage groups>> members): If the primary email address which is included in the row is On Hold, we should assign class="status-hold" to that cell and add "(On Hold)" after the email address.
CiviMail should not send emails to on_hold email addresses. [THIS SEEMS TO BE DONE, see CRM_Mailing_BAO_Mailing's getRecipients() and retryRecipients()]
The simple 'Send an Email' link and 'Send Email to Contacts' action should not send emails to on_hold email addresses.
For the singleton task (Send an Email) - put up form validation type error when user submits the email form: "The selected email address is On Hold because the maximum number of delivery attempts has failed. If you have been informed that the problem with this address is resolved, you can take the address off Hold by editing the contact record. Otherwise, you will need to try an different email address for this contact."
For the batch task (Send Emails to Contacts) - add an item in the "results" display - "Email was not sent to $contactName because their primary email address ($email) is On Hold."
A successful delivery by CiviMail should set the reset_date to the current date (there was a success just now, we should start any bounce counting for this address from scratch).
A successful simple 'Send an Email' and 'Send Email to Contacts' action SHOULD NOT act on the reset_date field (a success here means 'the email reached the SMTP sink', not 'the email wasn't bounced by the destination server').
A CiviMail bounce should refer to the civicrm_mailing_bounce_type table and, based on its hold_threshold and the count of bounces (from civicrm_mailing_event_bounce) for this particular address so far since the reset_date (this is important, we do not want to count bounces that happened before last success) decide whether put the address on hold; if so, it should turn on the on_hold flag and set the hold_date to the current date. [THIS SEEMS TO BE DONE, but please review the code of CRM_Mailing_Event_BAO_Bounce's create() to make sure it is]