Environment-specific code in @Async mail method with Spring
Use Spring's dependency injection more aggressively

You are right to be suspicious about hardcoded environment-specific logic.
But you're in luck. This is one of the typical problems that Spring can help you solve.

One way to solve this is to create an interface for controlling the destination email address, and inject an implementation appropriate for the environment. For example:

interface OutgoingEmailController {
    void adjustOutgoingEmail(MimeMessageHelper helper, String email, String body);
}


Implementation to inject in QA:

class QAOutgoingEmailController implements OutgoingEmailController {
    @Override
    public void adjustOutgoingEmail(MimeMessageHelper helper, String email, String body) {
        if (isTestMode()) {
            if (!email.equals(getTestEmailAddress())) {
                helper.setTo(getTestEmailAddress());
                body += "&lt;br/&gt;This email was originally intended for " + email +
                        " but was redirected to " + getTestEmailAddress() + " for testing.";
                helper.setText(body, true); //HTML on
            }
        }
    }
}


Implementation to inject in other environments:

class CommonOutgoingEmailController implements OutgoingEmailController {
    @Override
    public void adjustOutgoingEmail(MimeMessageHelper helper, String email, String body) {
        helper.setTo(email);
        helper.setText(body, true);
    }
}


In your original code you will have an @Autowired OutgoingEmailController outgoingEmailController;, and the IFFY code replaced with outgoingEmailController.adjustOutgoingEmail(helper, email, body);.

Or something like that.

Other remarks

It's odd that you check for null email at the beginning but check for null body at the end. It would be better to move the check on the body further up to the beginning.