It's only expensive if the exception is thrown, but that's not an excuse to use exceptions as normal flow control.
If you can pre-validate something to avoid an exception occurring in the first place, then do so. E.g. instead of what you posted, something like this would be preferable:
string invalidAddress = "notvalid@@@@@@lolzors.bomb";
return MailAddressValidator.IsValid(invalidAddress ); // doesn't cause exception
The exception to the rule is when you'd have to roll your own version of a complicated method (e.g. something found in the base class library that doesn't have a TryParse
method) just to avoid an exception that, in the grand scheme of things, just doesn't matter.
If you are unsure, profile using representative data. If it's a user entering data in a client app form every other second, it won't matter. However, if it's a service for processing batches of thousands of email addresses that could come from anywhere, you ought to be sure of your assumptions.