errors.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Package smtp provides email sending functionality
  2. package smtp
  3. import (
  4. "errors"
  5. "fmt"
  6. )
  7. // Common SMTP error types
  8. var (
  9. // ErrInvalidConfig indicates missing or invalid SMTP configuration
  10. ErrInvalidConfig = errors.New("invalid SMTP configuration")
  11. // ErrInvalidRecipient indicates an invalid or empty recipient email
  12. ErrInvalidRecipient = errors.New("invalid recipient email")
  13. // ErrTemplateParsingFailed indicates a failure to parse an email template
  14. ErrTemplateParsingFailed = errors.New("failed to parse email template")
  15. // ErrTemplateExecutionFailed indicates a failure to execute an email template
  16. ErrTemplateExecutionFailed = errors.New("failed to execute email template")
  17. // ErrMessageCreationFailed indicates a failure to create an email message
  18. ErrMessageCreationFailed = errors.New("failed to create email message")
  19. // ErrSendFailed indicates a failure to send an email
  20. ErrSendFailed = errors.New("failed to send email")
  21. // ErrConnectionFailed indicates a failure to connect to the SMTP server
  22. ErrConnectionFailed = errors.New("failed to connect to SMTP server")
  23. // ErrInvalidTemplate indicates missing or invalid template data
  24. ErrInvalidTemplate = errors.New("invalid template data")
  25. // ErrClientClosed indicates the SMTP client is already closed
  26. ErrClientClosed = errors.New("SMTP client is closed")
  27. )
  28. // Error represents an SMTP-specific error with detailed context
  29. type Error struct {
  30. // Op is the operation that failed (e.g., "send", "connect", "template")
  31. Op string
  32. // Err is the underlying error
  33. Err error
  34. // Details contains additional error context
  35. Details string
  36. // Template indicates which email template was involved (if applicable)
  37. Template string
  38. // Recipient indicates which email address was involved (if applicable)
  39. Recipient string
  40. }
  41. // Error returns a string representation of the error
  42. func (e *Error) Error() string {
  43. msg := fmt.Sprintf("smtp %s failed", e.Op)
  44. if e.Template != "" {
  45. msg = fmt.Sprintf("%s for template %s", msg, e.Template)
  46. }
  47. if e.Recipient != "" {
  48. msg = fmt.Sprintf("%s to %s", msg, e.Recipient)
  49. }
  50. if e.Details != "" {
  51. msg = fmt.Sprintf("%s: %s", msg, e.Details)
  52. }
  53. if e.Err != nil {
  54. msg = fmt.Sprintf("%s: %v", msg, e.Err)
  55. }
  56. return msg
  57. }
  58. // Unwrap returns the underlying error
  59. func (e *Error) Unwrap() error {
  60. return e.Err
  61. }
  62. // Is reports whether target matches this error
  63. func (e *Error) Is(target error) bool {
  64. return errors.Is(e.Err, target)
  65. }
  66. // NewError creates a new SMTP error
  67. func NewError(op string, err error, details string) *Error {
  68. return &Error{
  69. Op: op,
  70. Err: err,
  71. Details: details,
  72. }
  73. }
  74. // NewTemplateError creates a new SMTP template error
  75. func NewTemplateError(op string, templateName string, err error, details string) *Error {
  76. return &Error{
  77. Op: op,
  78. Template: templateName,
  79. Err: err,
  80. Details: details,
  81. }
  82. }
  83. // NewSendError creates a new SMTP send error
  84. func NewSendError(op string, recipient string, err error, details string) *Error {
  85. return &Error{
  86. Op: op,
  87. Recipient: recipient,
  88. Err: err,
  89. Details: details,
  90. }
  91. }
  92. // IsConnectionError returns true if the error indicates a connection problem
  93. func IsConnectionError(err error) bool {
  94. var e *Error
  95. return errors.As(err, &e) && errors.Is(e.Err, ErrConnectionFailed)
  96. }
  97. // IsTemplateError returns true if the error is related to template processing
  98. func IsTemplateError(err error) bool {
  99. var e *Error
  100. return errors.As(err, &e) && (errors.Is(e.Err, ErrTemplateParsingFailed) ||
  101. errors.Is(e.Err, ErrTemplateExecutionFailed) ||
  102. errors.Is(e.Err, ErrInvalidTemplate))
  103. }