Exceptions
MailWrapper defines several exception classes to handle different error conditions. All exceptions are in the ByJG\Mail\Exception namespace.
Exception Hierarchy
All MailWrapper exceptions extend standard PHP exceptions, allowing you to catch them individually or as a group.
\Exception
├── InvalidEMailException
├── InvalidMailHandlerException
├── InvalidMessageFormatException
├── MailApiException
└── ProtocolNotRegisteredException
Exception Types
InvalidEMailException
Thrown when email validation fails.
Common causes:
- Missing sender address
- Missing recipient address
- Invalid email format
Example:
use ByJG\Mail\Exception\InvalidEMailException;
try {
$envelope = new \ByJG\Mail\Envelope();
// No from or to addresses set
$mailer->send($envelope);
} catch (InvalidEMailException $e) {
echo "Email validation failed: " . $e->getMessage();
// Output: "Destination Email was not provided"
}
ProtocolNotRegisteredException
Thrown when trying to create a mailer for an unregistered protocol scheme.
Common causes:
- Forgetting to register a wrapper with
MailerFactory::registerMailer() - Using an invalid or misspelled scheme in the connection string
- Wrapper not installed or available
Example:
use ByJG\Mail\Exception\ProtocolNotRegisteredException;
try {
// Forgot to register the SMTP wrapper
$mailer = \ByJG\Mail\MailerFactory::create('smtp://user:pass@host');
} catch (ProtocolNotRegisteredException $e) {
echo "Protocol error: " . $e->getMessage();
// Output: "Protocol not found/registered!"
}
Solution:
// Register the wrapper before creating the mailer
\ByJG\Mail\MailerFactory::registerMailer(\ByJG\Mail\Wrapper\PHPMailerWrapper::class);
$mailer = \ByJG\Mail\MailerFactory::create('smtp://user:pass@host');
InvalidMailHandlerException
Thrown when trying to register an invalid wrapper class.
Common causes:
- Registering a class that doesn't implement
MailWrapperInterface - Passing a non-existent class name
Example:
use ByJG\Mail\Exception\InvalidMailHandlerException;
try {
\ByJG\Mail\MailerFactory::registerMailer(\MyApp\InvalidClass::class);
} catch (InvalidMailHandlerException $e) {
echo "Registration error: " . $e->getMessage();
// Output: "Class not implements ConnectorInterface!"
}
InvalidMessageFormatException
Thrown when the message format is invalid or incomplete.
Common causes:
- Invalid message structure
- Missing required fields
- Malformed content
Example:
use ByJG\Mail\Exception\InvalidMessageFormatException;
// This exception might be thrown by custom wrappers with additional validation
try {
// Some wrapper that validates subject is not empty
$mailer->send($envelope);
} catch (InvalidMessageFormatException $e) {
echo "Message format error: " . $e->getMessage();
}
MailApiException
Thrown when an email API returns an error.
Common causes:
- Invalid API credentials
- API rate limiting
- Network connectivity issues
- Service outages
- Invalid email addresses rejected by the API
Example:
use ByJG\Mail\Exception\MailApiException;
try {
$mailer = \ByJG\Mail\MailerFactory::create('mailgun://[email protected]');
$mailer->send($envelope);
} catch (MailApiException $e) {
echo "API error: " . $e->getMessage();
// Might include API-specific error details
}
Exception Handling Best Practices
Catch Specific Exceptions
Handle different exception types appropriately:
use ByJG\Mail\Exception\{
InvalidEMailException,
ProtocolNotRegisteredException,
MailApiException
};
try {
$mailer = \ByJG\Mail\MailerFactory::create($connection);
$result = $mailer->send($envelope);
} catch (InvalidEMailException $e) {
// Validation error - fix the envelope data
error_log("Invalid email configuration: " . $e->getMessage());
} catch (ProtocolNotRegisteredException $e) {
// Configuration error - register the protocol
error_log("Missing protocol registration: " . $e->getMessage());
} catch (MailApiException $e) {
// API error - might be temporary, consider retrying
error_log("Mail service API error: " . $e->getMessage());
} catch (\Exception $e) {
// Catch-all for unexpected errors
error_log("Unexpected error: " . $e->getMessage());
}
Validate Before Sending
Validate the envelope before attempting to send:
$envelope = new \ByJG\Mail\Envelope();
// Validate manually if needed
if (empty($envelope->getFrom())) {
throw new \ByJG\Mail\Exception\InvalidEMailException('From address required');
}
if (count($envelope->getTo()) === 0) {
throw new \ByJG\Mail\Exception\InvalidEMailException('At least one recipient required');
}
Logging and Debugging
Include context in error handling:
try {
$result = $mailer->send($envelope);
if (!$result->success) {
error_log(sprintf(
'Failed to send email to %s: %s',
implode(', ', $envelope->getTo()),
'Unknown error'
));
}
} catch (\Exception $e) {
error_log(sprintf(
'Exception sending email to %s: %s - %s',
implode(', ', $envelope->getTo()),
get_class($e),
$e->getMessage()
));
// Optionally include stack trace in development
if (DEBUG_MODE) {
error_log($e->getTraceAsString());
}
}
Retry Logic
Implement retry logic for transient failures:
use ByJG\Mail\Exception\MailApiException;
function sendWithRetry($mailer, $envelope, $maxAttempts = 3): bool
{
$attempt = 0;
while ($attempt < $maxAttempts) {
try {
$result = $mailer->send($envelope);
return $result->success;
} catch (MailApiException $e) {
$attempt++;
if ($attempt >= $maxAttempts) {
throw $e;
}
// Exponential backoff
sleep(pow(2, $attempt));
}
}
return false;
}
Graceful Degradation
Consider fallback mechanisms:
$primaryMailer = \ByJG\Mail\MailerFactory::create('mailgun://key@domain');
$fallbackMailer = \ByJG\Mail\MailerFactory::create('smtp://user:pass@host:587');
try {
$result = $primaryMailer->send($envelope);
} catch (\Exception $e) {
error_log('Primary mailer failed, using fallback: ' . $e->getMessage());
try {
$result = $fallbackMailer->send($envelope);
} catch (\Exception $e2) {
error_log('Fallback mailer also failed: ' . $e2->getMessage());
throw $e2;
}
}