diff --git a/.examples/.serverless/aws_lambda/go.mod b/.examples/.serverless/aws_lambda/go.mod index 0c2a83b..f71c7a3 100644 --- a/.examples/.serverless/aws_lambda/go.mod +++ b/.examples/.serverless/aws_lambda/go.mod @@ -1,6 +1,6 @@ module github.com/darkrockmountain/gomail/aws_lambda_email_sender -go 1.22.1 +go 1.22.4 require ( github.com/aws/aws-lambda-go v1.47.0 diff --git a/.examples/.serverless/azure_functions/go.mod b/.examples/.serverless/azure_functions/go.mod index ad46092..7fa2d39 100644 --- a/.examples/.serverless/azure_functions/go.mod +++ b/.examples/.serverless/azure_functions/go.mod @@ -1,5 +1,5 @@ module github.com/darkrockmountain/gomail/azure_email_sender -go 1.22.1 +go 1.22.4 require github.com/darkrockmountain/gomail v0.5.1 diff --git a/.examples/.serverless/google_cloud_functions/go.mod b/.examples/.serverless/google_cloud_functions/go.mod index a8fd40b..1efcd98 100644 --- a/.examples/.serverless/google_cloud_functions/go.mod +++ b/.examples/.serverless/google_cloud_functions/go.mod @@ -1,6 +1,6 @@ module github.com/darkrockmountain/gomail/google_cloud_email_sender -go 1.22.1 +go 1.22.4 require ( github.com/GoogleCloudPlatform/functions-framework-go v1.8.1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a68d3d7..d021980 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: - name: Set up Go uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: - go-version: 1.22.3 + go-version: 1.22.4 - name: Install dependencies run: go mod tidy @@ -33,7 +33,7 @@ jobs: - name: Set up Go uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: - go-version: 1.22.3 + go-version: 1.22.4 - name: Run tests and generate coverage run: go test -coverprofile=coverage.out ./... diff --git a/.github/workflows/govulncheck.yaml b/.github/workflows/govulncheck.yaml index ff7874d..002c6dc 100644 --- a/.github/workflows/govulncheck.yaml +++ b/.github/workflows/govulncheck.yaml @@ -14,5 +14,5 @@ jobs: - id: govulncheck uses: golang/govulncheck-action@3a32958c2706f7048305d5a2e53633d7e37e97d0 # v1.0.2 with: - go-version-input: 1.22.3 + go-version-input: 1.22.4 go-package: ./... diff --git a/docs/AWS_SES_Credentials.md b/docs/AWS_SES_Credentials.md index 499ef3c..425d0d6 100644 --- a/docs/AWS_SES_Credentials.md +++ b/docs/AWS_SES_Credentials.md @@ -46,9 +46,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage(sender,[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). SetHTML("

This is the HTML part of the email.

"). - AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) diff --git a/docs/Gmail_Credentials_API_Key.md b/docs/Gmail_Credentials_API_Key.md index 7f5fd3b..cfcc382 100644 --- a/docs/Gmail_Credentials_API_Key.md +++ b/docs/Gmail_Credentials_API_Key.md @@ -44,9 +44,7 @@ if err != nil { // Define email message using an alias email address message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) diff --git a/docs/Gmail_Credentials_JWT.md b/docs/Gmail_Credentials_JWT.md index 34d4346..2c10074 100644 --- a/docs/Gmail_Credentials_JWT.md +++ b/docs/Gmail_Credentials_JWT.md @@ -84,9 +84,7 @@ if err != nil { // Define email message using an alias email address message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Gmail_Credentials_OAuth2.md b/docs/Gmail_Credentials_OAuth2.md index 3e154fa..fbe231d 100644 --- a/docs/Gmail_Credentials_OAuth2.md +++ b/docs/Gmail_Credentials_OAuth2.md @@ -144,9 +144,7 @@ if err != nil { // Define email message using an alias email address message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Gmail_Credentials_ServiceAccount copy.md b/docs/Gmail_Credentials_ServiceAccount copy.md index 1069668..95e5626 100644 --- a/docs/Gmail_Credentials_ServiceAccount copy.md +++ b/docs/Gmail_Credentials_ServiceAccount copy.md @@ -85,9 +85,7 @@ if err != nil { // Define email message using an alias email address message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Gmail_Credentials_ServiceAccount.md b/docs/Gmail_Credentials_ServiceAccount.md index 0462fed..0df69ac 100644 --- a/docs/Gmail_Credentials_ServiceAccount.md +++ b/docs/Gmail_Credentials_ServiceAccount.md @@ -78,9 +78,7 @@ if err != nil { // Define email message using an alias email address message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Mailgun_Credentials.md b/docs/Mailgun_Credentials.md index ff7731e..47d9132 100644 --- a/docs/Mailgun_Credentials.md +++ b/docs/Mailgun_Credentials.md @@ -42,9 +42,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Mandrill_Credentials.md b/docs/Mandrill_Credentials.md index c1d8f82..65ce3f2 100644 --- a/docs/Mandrill_Credentials.md +++ b/docs/Mandrill_Credentials.md @@ -38,9 +38,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Microsoft365_Credentials_ROPC.md b/docs/Microsoft365_Credentials_ROPC.md index 8450b56..7bbc2ac 100644 --- a/docs/Microsoft365_Credentials_ROPC.md +++ b/docs/Microsoft365_Credentials_ROPC.md @@ -52,9 +52,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Microsoft365_Credentials_app.md b/docs/Microsoft365_Credentials_app.md index 54a9530..c79a148 100644 --- a/docs/Microsoft365_Credentials_app.md +++ b/docs/Microsoft365_Credentials_app.md @@ -52,9 +52,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Microsoft365_Credentials_credentials.md b/docs/Microsoft365_Credentials_credentials.md index 72d6bfe..e25ceb3 100644 --- a/docs/Microsoft365_Credentials_credentials.md +++ b/docs/Microsoft365_Credentials_credentials.md @@ -51,9 +51,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Microsoft365_Credentials_managed_id.md b/docs/Microsoft365_Credentials_managed_id.md index 78e0eb0..6e2ade8 100644 --- a/docs/Microsoft365_Credentials_managed_id.md +++ b/docs/Microsoft365_Credentials_managed_id.md @@ -39,9 +39,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Microsoft365_Credentials_user.md b/docs/Microsoft365_Credentials_user.md index cb9f0e8..0b7be4b 100644 --- a/docs/Microsoft365_Credentials_user.md +++ b/docs/Microsoft365_Credentials_user.md @@ -52,9 +52,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/Postmark_Credentials.md b/docs/Postmark_Credentials.md index 1086eb9..c1cd871 100644 --- a/docs/Postmark_Credentials.md +++ b/docs/Postmark_Credentials.md @@ -40,9 +40,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/SMTP_Credentials.md b/docs/SMTP_Credentials.md index c8ea0af..2eba944 100644 --- a/docs/SMTP_Credentials.md +++ b/docs/SMTP_Credentials.md @@ -45,9 +45,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/docs/SendGrid_Credentials.md b/docs/SendGrid_Credentials.md index af38f31..1937af1 100644 --- a/docs/SendGrid_Credentials.md +++ b/docs/SendGrid_Credentials.md @@ -37,9 +37,7 @@ if err != nil { // Define email message message := gomail.NewEmailMessage("your-email_or_alias@example.com",[]string{"recipient@example.com"}, "Test Email with attachment", "This is the plain text part of the email."). - SetHTML("

This is the HTML part of the email.

").AddAttachments(gomail.Attachment{ - Filename: "attachment.jpg", Content: attachmentContent, - }) + SetHTML("

This is the HTML part of the email.

").AddAttachments(*gomail.NewAttachment("attachment.jpg", attachmentContent)) // Send email if err := emailSender.SendEmail(message); err != nil { diff --git a/email_sender.go b/email_sender.go index d46f6c1..ac7fc9e 100644 --- a/email_sender.go +++ b/email_sender.go @@ -53,7 +53,9 @@ package gomail import ( "encoding/base64" + "encoding/json" "html" + "io/ioutil" "mime" "path/filepath" "regexp" @@ -79,15 +81,15 @@ type EmailSender interface { // Use this struct to specify the sender, recipient, subject, and content of the email, // as well as any attachments. type EmailMessage struct { - From string `json:"from"` // Sender email address. - To []string `json:"to"` // Recipient email addresses. - CC []string `json:"cc"` // CC recipients email addresses. - BCC []string `json:"bcc"` // BCC recipients email addresses. - ReplyTo string `json:"replyTo"` // Reply-To email address. - Subject string `json:"subject"` // Email subject. - Text string `json:"text"` // Plain text content of the email. - HTML string `json:"html"` // HTML content of the email (optional). - Attachments []Attachment `json:"attachments"` // Attachments to be included in the email (optional). + from string // Sender email address. + to []string // Recipient email addresses. + cc []string // CC recipients email addresses. + bcc []string // BCC recipients email addresses. + replyTo string // Reply-To email address. + subject string // Email subject. + text string // Plain text content of the email. + html string // HTML content of the email (optional). + attachments []Attachment // Attachments to be included in the email (optional). maxAttachmentSize int // Maximum size for attachments. } @@ -104,16 +106,16 @@ type EmailMessage struct { // - *EmailMessage: A pointer to the newly created EmailMessage struct. func NewEmailMessage(from string, to []string, subject string, body string) *EmailMessage { email := &EmailMessage{ - From: from, - To: to, - Subject: subject, + from: from, + to: to, + subject: subject, maxAttachmentSize: DefaultMaxAttachmentSize, } if isHTML(body) { - email.HTML = body + email.html = body } else { - email.Text = body + email.text = body } return email @@ -135,15 +137,15 @@ func NewEmailMessage(from string, to []string, subject string, body string) *Ema // - *EmailMessage: A pointer to the newly created EmailMessage struct. func NewFullEmailMessage(from string, to []string, subject string, cc []string, bcc []string, replyTo string, textBody string, htmlBody string, attachments []Attachment) *EmailMessage { return &EmailMessage{ - From: from, - To: to, - CC: cc, - BCC: bcc, - ReplyTo: replyTo, - Subject: subject, - Text: textBody, - HTML: htmlBody, - Attachments: attachments, + from: from, + to: to, + cc: cc, + bcc: bcc, + replyTo: replyTo, + subject: subject, + text: textBody, + html: htmlBody, + attachments: attachments, maxAttachmentSize: DefaultMaxAttachmentSize, } } @@ -154,7 +156,7 @@ func NewFullEmailMessage(from string, to []string, subject string, cc []string, // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) SetFrom(from string) *EmailMessage { - e.From = from + e.from = from return e } @@ -164,7 +166,7 @@ func (e *EmailMessage) SetFrom(from string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) SetSubject(subject string) *EmailMessage { - e.Subject = subject + e.subject = subject return e } @@ -174,7 +176,7 @@ func (e *EmailMessage) SetSubject(subject string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) SetTo(to []string) *EmailMessage { - e.To = to + e.to = to return e } @@ -184,7 +186,7 @@ func (e *EmailMessage) SetTo(to []string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) SetCC(cc []string) *EmailMessage { - e.CC = cc + e.cc = cc return e } @@ -194,7 +196,7 @@ func (e *EmailMessage) SetCC(cc []string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) SetBCC(bcc []string) *EmailMessage { - e.BCC = bcc + e.bcc = bcc return e } @@ -204,7 +206,7 @@ func (e *EmailMessage) SetBCC(bcc []string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) SetReplyTo(replyTo string) *EmailMessage { - e.ReplyTo = replyTo + e.replyTo = replyTo return e } @@ -214,7 +216,7 @@ func (e *EmailMessage) SetReplyTo(replyTo string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) SetText(text string) *EmailMessage { - e.Text = text + e.text = text return e } @@ -224,7 +226,7 @@ func (e *EmailMessage) SetText(text string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) SetHTML(html string) *EmailMessage { - e.HTML = html + e.html = html return e } @@ -234,7 +236,7 @@ func (e *EmailMessage) SetHTML(html string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) SetAttachments(attachments []Attachment) *EmailMessage { - e.Attachments = attachments + e.attachments = attachments return e } @@ -244,7 +246,7 @@ func (e *EmailMessage) SetAttachments(attachments []Attachment) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) AddToRecipient(recipient string) *EmailMessage { - e.To = append(e.To, recipient) + e.to = append(e.to, recipient) return e } @@ -254,7 +256,7 @@ func (e *EmailMessage) AddToRecipient(recipient string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) AddCCRecipient(recipient string) *EmailMessage { - e.CC = append(e.CC, recipient) + e.cc = append(e.cc, recipient) return e } @@ -264,7 +266,7 @@ func (e *EmailMessage) AddCCRecipient(recipient string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) AddBCCRecipient(recipient string) *EmailMessage { - e.BCC = append(e.BCC, recipient) + e.bcc = append(e.bcc, recipient) return e } @@ -274,7 +276,7 @@ func (e *EmailMessage) AddBCCRecipient(recipient string) *EmailMessage { // Returns: // - *EmailMessage: The EmailMessage struct pointer. func (e *EmailMessage) AddAttachment(attachment Attachment) *EmailMessage { - e.Attachments = append(e.Attachments, attachment) + e.attachments = append(e.attachments, attachment) return e } @@ -287,7 +289,7 @@ func (e *EmailMessage) GetFrom() string { if e == nil { return "" } - return ValidateEmail(e.From) + return ValidateEmail(e.from) } // GetTo returns a slice of trimmed and validated recipient email addresses. @@ -299,7 +301,7 @@ func (e *EmailMessage) GetTo() []string { if e == nil { return []string{} } - return ValidateEmailSlice(e.To) + return ValidateEmailSlice(e.to) } // GetCC returns a slice of trimmed and validated CC recipient email addresses. @@ -311,7 +313,7 @@ func (e *EmailMessage) GetCC() []string { if e == nil { return []string{} } - return ValidateEmailSlice(e.CC) + return ValidateEmailSlice(e.cc) } // GetBCC returns a slice of trimmed and validated BCC recipient email addresses. @@ -323,7 +325,7 @@ func (e *EmailMessage) GetBCC() []string { if e == nil { return []string{} } - return ValidateEmailSlice(e.BCC) + return ValidateEmailSlice(e.bcc) } // GetReplyTo returns the trimmed and validated reply-to email address. @@ -335,7 +337,7 @@ func (e *EmailMessage) GetReplyTo() string { if e == nil { return "" } - return ValidateEmail(e.ReplyTo) + return ValidateEmail(e.replyTo) } // GetSubject returns the sanitized email subject. @@ -348,7 +350,7 @@ func (e *EmailMessage) GetSubject() string { if e == nil { return "" } - return SanitizeInput(e.Subject) + return SanitizeInput(e.subject) } // GetText returns the sanitized plain text content of the email. @@ -361,7 +363,7 @@ func (e *EmailMessage) GetText() string { if e == nil { return "" } - return SanitizeInput(e.Text) + return SanitizeInput(e.text) } // GetHTML returns the sanitized HTML with only the UGC @@ -374,7 +376,7 @@ func (e *EmailMessage) GetHTML() string { if e == nil { return "" } - return bluemonday.UGCPolicy().Sanitize(e.HTML) + return bluemonday.UGCPolicy().Sanitize(e.html) } // SetMaxAttachmentSize sets the maximum attachment size. @@ -399,49 +401,164 @@ func (e *EmailMessage) GetAttachments() []Attachment { } // if maxAttachmentSize return the attachments without the limit if e.maxAttachmentSize < 0 { - return e.Attachments + return e.attachments } // return only the attachments withing the max size limit var validAttachments []Attachment - for _, attachment := range e.Attachments { - if len(attachment.Content) <= e.maxAttachmentSize { + for _, attachment := range e.attachments { + if len(attachment.content) <= e.maxAttachmentSize { validAttachments = append(validAttachments, attachment) } } return validAttachments } +// regex for validating email addresses +var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9._\-]+\.[a-zA-Z]{2,}$`) + +// ValidateEmail trims the email and checks if it is a valid email address. +// Returns the trimmed email if valid, otherwise returns an empty string. +func ValidateEmail(email string) string { + trimmed := strings.TrimSpace(email) + if !emailRegex.MatchString(trimmed) { + return "" + } + return trimmed +} + +// ValidateEmailSlice trims and validates each email in the slice. +// Returns a slice of trimmed valid emails, excluding any invalid emails. +func ValidateEmailSlice(emails []string) []string { + validEmails := []string{} + for _, email := range emails { + if validEmail := ValidateEmail(email); validEmail != "" { + validEmails = append(validEmails, validEmail) + } + } + return validEmails +} + +// SanitizeInput sanitizes a string to prevent HTML and script injection. +func SanitizeInput(input string) string { + return html.EscapeString(strings.TrimSpace(input)) +} + +// isHTML checks if a string contains HTML tags. +// Parameters: +// - str: The string to check. +// +// Returns: +// - bool: True if the string contains HTML tags, otherwise false. +func isHTML(str string) bool { + htmlRegex := regexp.MustCompile(`(?i)<\/?[a-z][\s\S]*>`) + return htmlRegex.MatchString(str) +} + // Attachment represents an email attachment with its filename and content. // Use this struct to specify files to be attached to the email. type Attachment struct { - Filename string // The name of the file. - Content []byte // The content of the file. + filename string // The name of the file. + content []byte // The content of the file. } -// GetBase64StringContent returns the content of the attachment as a base64-encoded string. -// If the attachment is nil, it returns an empty string. +// NewAttachment creates a new Attachment instance with the specified filename and content. +// It initializes the private fields of the Attachment struct with the provided values. // -// Returns: -// - string: The base64-encoded content of the attachment as a string. -// Returns an empty string if the attachment is nil. -func (a *Attachment) GetBase64StringContent() string { - if a == nil { - return "" +// Example: +// +// content := []byte("file content") +// attachment := NewAttachment("document.pdf", content) +// fmt.Println(attachment.GetFilename()) // Output: document.pdf +// fmt.Println(string(attachment.GetContent())) // Output: file content +func NewAttachment(filename string, content []byte) *Attachment { + return &Attachment{ + filename: filename, + content: content, } - return string(a.GetBase64Content()) +} + +// NewAttachmentFromFile creates a new Attachment instance from the specified file path. +// It reads the content of the file and initializes the private fields of the Attachment struct. +// +// Example: +// +// attachment, err := NewAttachmentFromFile("path/to/document.pdf") +// if err != nil { +// fmt.Println("Error creating attachment:", err) +// return +// } +// fmt.Println(attachment.GetFilename()) // Output: document.pdf +// fmt.Println(string(attachment.GetContent())) // Output: (file content) +func NewAttachmentFromFile(filePath string) (*Attachment, error) { + content, err := ioutil.ReadFile(filePath) + if err != nil { + return nil, err + } + + filename := extractFilename(filePath) + return NewAttachment( + filename, + content, + ), nil +} + +// extractFilename extracts the filename from the file path. +// This is a helper function to get the filename from a given file path. +func extractFilename(filePath string) string { + // Implement this function based on your needs, for simplicity using base method + parts := strings.Split(filePath, "/") + return parts[len(parts)-1] +} + +// SetFilename sets the filename of the attachment. +// It assigns the provided filename to the private filename field. +// +// Example: +// +// var attachment Attachment +// attachment.SetFilename("document.pdf") +// fmt.Println(attachment.GetFilename()) // Output: document.pdf +func (a *Attachment) SetFilename(filename string) { + a.filename = filename } // GetFilename safely returns the filename of the attachment. // It escapes special characters like "<" to become "<" // If the attachment is nil, it returns an empty string. // Returns: -// - string: The Filename as a string. +// - string: The filename as a string. // Returns an "nil_attachment" string if the attachment is nil. func (a *Attachment) GetFilename() string { if a == nil { return "nil_attachment" } - return SanitizeInput(a.Filename) + return SanitizeInput(a.filename) +} + +// GetBase64StringContent returns the content of the attachment as a base64-encoded string. +// If the attachment is nil, it returns an empty string. +// +// Returns: +// - string: The base64-encoded content of the attachment as a string. +// Returns an empty string if the attachment is nil. +func (a *Attachment) GetBase64StringContent() string { + if a == nil { + return "" + } + return string(a.GetBase64Content()) +} + +// SetContent sets the content of the attachment. +// It assigns the provided content to the private content field. +// +// Example: +// +// var attachment Attachment +// content := []byte("file content") +// attachment.SetContent(content) +// fmt.Println(string(attachment.GetContent())) // Output: file content +func (a *Attachment) SetContent(content []byte) { + a.content = content } // GetBase64Content returns the content of the attachment as a base64-encoded byte slice. @@ -451,11 +568,11 @@ func (a *Attachment) GetFilename() string { // - []byte: The base64-encoded content of the attachment as a byte slice. // Returns an empty byte slice if the attachment is nil. func (a *Attachment) GetBase64Content() []byte { - if a == nil || len(a.Content) == 0 { + if a == nil || len(a.content) == 0 { return []byte{} } - buf := make([]byte, base64.StdEncoding.EncodedLen(len(a.Content))) - base64.StdEncoding.Encode(buf, a.Content) + buf := make([]byte, base64.StdEncoding.EncodedLen(len(a.content))) + base64.StdEncoding.Encode(buf, a.content) return buf } @@ -466,10 +583,10 @@ func (a *Attachment) GetBase64Content() []byte { // - []byte: The content of the attachment as a byte slice. // Returns an empty byte slice if the attachment is nil. func (a *Attachment) GetRawContent() []byte { - if a == nil || len(a.Content) == 0 { + if a == nil || len(a.content) == 0 { return []byte{} } - return a.Content + return a.content } // GetMimeType returns the MIME type based on the file extension. @@ -490,43 +607,166 @@ func GetMimeType(filename string) string { return mime.TypeByExtension(ext) } -// regex for validating email addresses -var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9._\-]+\.[a-zA-Z]{2,}$`) +// jsonEmailMessage represents the JSON structure for an email message. +type jsonEmailMessage struct { + From string `json:"from"` + To []string `json:"to"` + CC []string `json:"cc,omitempty"` + BCC []string `json:"bcc,omitempty"` + ReplyTo string `json:"replyTo,omitempty"` + Subject string `json:"subject"` + Text string `json:"text"` + HTML string `json:"html,omitempty"` + Attachments []Attachment `json:"attachments,omitempty"` +} -// ValidateEmail trims the email and checks if it is a valid email address. -// Returns the trimmed email if valid, otherwise returns an empty string. -func ValidateEmail(email string) string { - trimmed := strings.TrimSpace(email) - if !emailRegex.MatchString(trimmed) { - return "" +// MarshalJSON custom marshaler for EmailMessage +// This method converts the EmailMessage struct into a JSON representation. +// It creates an anonymous struct with exported fields and JSON tags, +// copies the values from the private fields, and then marshals it to JSON. +// +// Example: +// +// email := &EmailMessage{ +// from: "sender@example.com", +// to: []string{"recipient@example.com"}, +// cc: []string{"cc@example.com"}, +// bcc: []string{"bcc@example.com"}, +// replyTo: "replyto@example.com", +// subject: "Subject", +// text: "This is the email content.", +// html: "

This is the email content.

", +// attachments: []Attachment{ +// {filename: "attachment1.txt", content: []byte("content1")}, +// }, +// maxAttachmentSize: 1024, +// } +// jsonData, err := json.Marshal(email) +// if err != nil { +// fmt.Println("Error marshaling to JSON:", err) +// return +// } +// fmt.Println("JSON output:", string(jsonData)) +func (e *EmailMessage) MarshalJSON() ([]byte, error) { + return json.Marshal(&jsonEmailMessage{ + From: e.from, + To: e.to, + CC: e.cc, + BCC: e.bcc, + ReplyTo: e.replyTo, + Subject: e.subject, + Text: e.text, + HTML: e.html, + Attachments: e.attachments, + }) +} + +// UnmarshalJSON custom unmarshaler for EmailMessage +// This method converts a JSON representation into an EmailMessage struct. +// It creates an anonymous struct with exported fields and JSON tags, +// unmarshals the JSON data into this struct, and then copies the values +// to the private fields of the EmailMessage struct. +// +// Example: +// +// jsonData := `{ +// "from": "sender@example.com", +// "to": ["recipient@example.com"], +// "cc": ["cc@example.com"], +// "bcc": ["bcc@example.com"], +// "replyTo": "replyto@example.com", +// "subject": "Subject", +// "text": "This is the email content.", +// "html": "

This is the email content.

", +// "attachments": [{"filename": "attachment1.txt", "content": "Y29udGVudDE="}] // base64 encoded "content1" +// }` +// var email EmailMessage +// err := json.Unmarshal([]byte(jsonData), &email) +// if err != nil { +// fmt.Println("Error unmarshaling from JSON:", err) +// return +// } +// fmt.Printf("Unmarshaled EmailMessage: %+v\n", email) +func (e *EmailMessage) UnmarshalJSON(data []byte) error { + aux := &jsonEmailMessage{} + if err := json.Unmarshal(data, aux); err != nil { + return err } - return trimmed + + e.from = aux.From + e.to = aux.To + e.cc = aux.CC + e.bcc = aux.BCC + e.replyTo = aux.ReplyTo + e.subject = aux.Subject + e.text = aux.Text + e.html = aux.HTML + e.attachments = aux.Attachments + + return nil } -// ValidateEmailSlice trims and validates each email in the slice. -// Returns a slice of trimmed valid emails, excluding any invalid emails. -func ValidateEmailSlice(emails []string) []string { - validEmails := []string{} - for _, email := range emails { - if validEmail := ValidateEmail(email); validEmail != "" { - validEmails = append(validEmails, validEmail) - } - } - return validEmails +// jsonAttachment represents the JSON structure for an email attachment. +type jsonAttachment struct { + Filename string `json:"filename"` + Content string `json:"content"` // Content will be base64 encoded } -// SanitizeInput sanitizes a string to prevent HTML and script injection. -func SanitizeInput(input string) string { - return html.EscapeString(strings.TrimSpace(input)) +// MarshalJSON custom marshaler for Attachment +// This method converts the Attachment struct into a JSON representation. +// It creates an anonymous struct with exported fields and JSON tags, +// copies the values from the private fields, and then marshals it to JSON. +// +// Example: +// +// attachment := Attachment{ +// filename: "file.txt", +// content: []byte("file content"), +// } +// jsonData, err := json.Marshal(attachment) +// if err != nil { +// fmt.Println("Error marshaling to JSON:", err) +// return +// } +// fmt.Println("JSON output:", string(jsonData)) +func (a Attachment) MarshalJSON() ([]byte, error) { + return json.Marshal(&jsonAttachment{ + Filename: a.filename, + Content: base64.StdEncoding.EncodeToString(a.content), // Encode content to base64 + }) } -// isHTML checks if a string contains HTML tags. -// Parameters: -// - str: The string to check. +// UnmarshalJSON custom unmarshaler for Attachment +// This method converts a JSON representation into an Attachment struct. +// It creates an anonymous struct with exported fields and JSON tags, +// unmarshals the JSON data into this struct, and then copies the values +// to the private fields of the Attachment struct. // -// Returns: -// - bool: True if the string contains HTML tags, otherwise false. -func isHTML(str string) bool { - htmlRegex := regexp.MustCompile(`(?i)<\/?[a-z][\s\S]*>`) - return htmlRegex.MatchString(str) +// Example: +// +// jsonData := `{ +// "filename": "file.txt", +// "content": "ZmlsZSBjb250ZW50" // base64 encoded "file content" +// }` +// var attachment Attachment +// err := json.Unmarshal([]byte(jsonData), &attachment) +// if err != nil { +// fmt.Println("Error unmarshaling from JSON:", err) +// return +// } +// fmt.Printf("Unmarshaled Attachment: %+v\n", attachment) +func (a *Attachment) UnmarshalJSON(data []byte) error { + aux := &jsonAttachment{} + if err := json.Unmarshal(data, aux); err != nil { + return err + } + + a.filename = aux.Filename + content, err := base64.StdEncoding.DecodeString(aux.Content) // Decode content from base64 + if err != nil { + return err + } + a.content = content + + return nil } diff --git a/email_sender_test.go b/email_sender_test.go index df981c1..78476b1 100644 --- a/email_sender_test.go +++ b/email_sender_test.go @@ -2,6 +2,9 @@ package gomail import ( "encoding/base64" + "encoding/json" + "os" + "path/filepath" "strings" "testing" @@ -60,93 +63,18 @@ func TestValidateEmailSlice(t *testing.T) { } } -func TestGetBase64Content(t *testing.T) { - tests := []struct { - attachment *Attachment - expected []byte - }{ - {&Attachment{Filename: "test.txt", Content: []byte("hello")}, []byte(base64.StdEncoding.EncodeToString([]byte("hello")))}, - {&Attachment{Filename: "test.txt", Content: []byte("")}, []byte{}}, - {&Attachment{Filename: "empty.txt", Content: nil}, []byte{}}, - } - - for _, test := range tests { - t.Run(test.attachment.GetFilename(), func(t *testing.T) { - result := test.attachment.GetBase64Content() - assert.Equal(t, test.expected, result) - }) - } -} - -func TestGetBase64StringContent(t *testing.T) { - tests := []struct { - attachment *Attachment - expected string - }{ - {&Attachment{Filename: "test.txt", Content: []byte("hello")}, base64.StdEncoding.EncodeToString([]byte("hello"))}, - {&Attachment{Filename: "test.txt", Content: []byte("")}, ""}, - {nil, ""}, - } - - for _, test := range tests { - t.Run(test.attachment.GetFilename(), func(t *testing.T) { - result := test.attachment.GetBase64StringContent() - assert.Equal(t, test.expected, result) - }) - } -} - -func TestGetRawContent(t *testing.T) { - tests := []struct { - attachment *Attachment - expected []byte - }{ - {&Attachment{Filename: "test.txt", Content: []byte("hello")}, []byte("hello")}, - {&Attachment{Filename: "test.txt", Content: []byte("")}, []byte{}}, - {&Attachment{Filename: "empty.txt", Content: nil}, []byte{}}, - } - - for _, test := range tests { - t.Run(test.attachment.GetFilename(), func(t *testing.T) { - result := test.attachment.GetRawContent() - assert.Equal(t, test.expected, result) - }) - } -} - -func TestGetMimeType(t *testing.T) { - tests := []struct { - filename string - expected string - }{ - {"document.pdf", "application/pdf"}, - {"image.png", "image/png"}, - {"archive.zip", "application/zip"}, - {"unknownfile.unknown", ""}, - {"text.txt", "text/plain; charset=utf-8"}, - {"no_extension", ""}, - } - - for _, test := range tests { - t.Run(test.filename, func(t *testing.T) { - result := GetMimeType(test.filename) - assert.Equal(t, test.expected, result) - }) - } -} - func TestEmailMessageGetters(t *testing.T) { message := EmailMessage{ - From: "sender@example.com", - To: []string{"recipient1@example.com", "recipient2@example.com"}, - CC: []string{"cc1@example.com", "cc2@example.com"}, - BCC: []string{"bcc1@example.com", "bcc2@example.com"}, - ReplyTo: "replyto@example.com", - Subject: "Test Subject", - Text: "Test Text", - HTML: "

Test HTML

", - Attachments: []Attachment{ - {Filename: "test.txt", Content: []byte("test content")}, + from: "sender@example.com", + to: []string{"recipient1@example.com", "recipient2@example.com"}, + cc: []string{"cc1@example.com", "cc2@example.com"}, + bcc: []string{"bcc1@example.com", "bcc2@example.com"}, + replyTo: "replyto@example.com", + subject: "Test Subject", + text: "Test Text", + html: "

Test HTML

", + attachments: []Attachment{ + {filename: "test.txt", content: []byte("test content")}, }, maxAttachmentSize: DefaultMaxAttachmentSize, } @@ -201,7 +129,7 @@ func TestEmailMessageGetters(t *testing.T) { t.Run("GetAttachments", func(t *testing.T) { expected := []Attachment{ - {Filename: "test.txt", Content: []byte("test content")}, + {filename: "test.txt", content: []byte("test content")}, } result := message.GetAttachments() assert.Equal(t, expected, result) @@ -259,7 +187,7 @@ func TestNilEmailMessageGetters(t *testing.T) { func TestEmailHTMLBodySanitzers(t *testing.T) { message := EmailMessage{ - HTML: `
XSS
`, + html: `
XSS
`, } t.Run("remove potential XSS attack", func(t *testing.T) { @@ -269,7 +197,7 @@ func TestEmailHTMLBodySanitzers(t *testing.T) { }) message2 := EmailMessage{ - HTML: `Google`, + html: `Google`, } t.Run("on methods not allowed", func(t *testing.T) { @@ -279,7 +207,7 @@ func TestEmailHTMLBodySanitzers(t *testing.T) { }) message3 := EmailMessage{ - HTML: `

Google

`, + html: `

Google

`, } t.Run("

can't have href", func(t *testing.T) { expected := `

Google

` @@ -297,11 +225,11 @@ func TestNewEmailMessage(t *testing.T) { body := "Email body" email := NewEmailMessage(from, to, subject, body) - assert.Equal(t, from, email.From) - assert.Equal(t, to, email.To) - assert.Equal(t, subject, email.Subject) - assert.Equal(t, body, email.Text) - assert.Equal(t, "", email.HTML) + assert.Equal(t, from, email.from) + assert.Equal(t, to, email.to) + assert.Equal(t, subject, email.subject) + assert.Equal(t, body, email.text) + assert.Equal(t, "", email.html) }) t.Run("create HTML email", func(t *testing.T) { @@ -311,11 +239,11 @@ func TestNewEmailMessage(t *testing.T) { body := "

Email body

" email := NewEmailMessage(from, to, subject, body) - assert.Equal(t, from, email.From) - assert.Equal(t, to, email.To) - assert.Equal(t, subject, email.Subject) - assert.Equal(t, "", email.Text) - assert.Equal(t, body, email.HTML) + assert.Equal(t, from, email.from) + assert.Equal(t, to, email.to) + assert.Equal(t, subject, email.subject) + assert.Equal(t, "", email.text) + assert.Equal(t, body, email.html) }) } @@ -330,19 +258,19 @@ func TestNewFullEmailMessage(t *testing.T) { text := "Text body" html := "

HTML body

" attachments := []Attachment{ - {Filename: "test.txt", Content: []byte("test content")}, + {filename: "test.txt", content: []byte("test content")}, } email := NewFullEmailMessage(from, to, subject, cc, bcc, replyTo, text, html, attachments) - assert.Equal(t, from, email.From) - assert.Equal(t, to, email.To) - assert.Equal(t, cc, email.CC) - assert.Equal(t, bcc, email.BCC) - assert.Equal(t, replyTo, email.ReplyTo) - assert.Equal(t, subject, email.Subject) - assert.Equal(t, text, email.Text) - assert.Equal(t, html, email.HTML) - assert.Equal(t, attachments, email.Attachments) + assert.Equal(t, from, email.from) + assert.Equal(t, to, email.to) + assert.Equal(t, cc, email.cc) + assert.Equal(t, bcc, email.bcc) + assert.Equal(t, replyTo, email.replyTo) + assert.Equal(t, subject, email.subject) + assert.Equal(t, text, email.text) + assert.Equal(t, html, email.html) + assert.Equal(t, attachments, email.attachments) }) } @@ -352,80 +280,80 @@ func TestEmailMessageSetters(t *testing.T) { t.Run("SetFrom", func(t *testing.T) { expected := "sender@example.com" email.SetFrom(expected) - assert.Equal(t, expected, email.From) + assert.Equal(t, expected, email.from) }) t.Run("SetSubject", func(t *testing.T) { expected := "Subject" email.SetSubject(expected) - assert.Equal(t, expected, email.Subject) + assert.Equal(t, expected, email.subject) }) t.Run("SetTo", func(t *testing.T) { expected := []string{"recipient@example.com"} email.SetTo(expected) - assert.Equal(t, expected, email.To) + assert.Equal(t, expected, email.to) }) t.Run("SetCC", func(t *testing.T) { expected := []string{"cc@example.com"} email.SetCC(expected) - assert.Equal(t, expected, email.CC) + assert.Equal(t, expected, email.cc) }) t.Run("SetBCC", func(t *testing.T) { expected := []string{"bcc@example.com"} email.SetBCC(expected) - assert.Equal(t, expected, email.BCC) + assert.Equal(t, expected, email.bcc) }) t.Run("SetReplyTo", func(t *testing.T) { expected := "replyto@example.com" email.SetReplyTo(expected) - assert.Equal(t, expected, email.ReplyTo) + assert.Equal(t, expected, email.replyTo) }) t.Run("SetText", func(t *testing.T) { expected := "Text body" email.SetText(expected) - assert.Equal(t, expected, email.Text) + assert.Equal(t, expected, email.text) }) t.Run("SetHTML", func(t *testing.T) { expected := "

HTML body

" email.SetHTML(expected) - assert.Equal(t, expected, email.HTML) + assert.Equal(t, expected, email.html) }) t.Run("SetAttachments", func(t *testing.T) { - attachment := Attachment{Filename: "test.txt", Content: []byte("test content")} + attachment := Attachment{filename: "test.txt", content: []byte("test content")} email.SetAttachments([]Attachment{attachment}) - assert.Contains(t, email.Attachments, attachment) - assert.EqualValues(t, email.Attachments, []Attachment{attachment}) + assert.Contains(t, email.attachments, attachment) + assert.EqualValues(t, email.attachments, []Attachment{attachment}) }) t.Run("AddAttachment", func(t *testing.T) { - attachment := Attachment{Filename: "test.txt", Content: []byte("test content")} + attachment := Attachment{filename: "test.txt", content: []byte("test content")} email.AddAttachment(attachment) - assert.Contains(t, email.Attachments, attachment) + assert.Contains(t, email.attachments, attachment) }) t.Run("AddToRecipient", func(t *testing.T) { recipient := "newrecipient@example.com" email.AddToRecipient(recipient) - assert.Contains(t, email.To, recipient) + assert.Contains(t, email.to, recipient) }) t.Run("AddCCRecipient", func(t *testing.T) { recipient := "newcc@example.com" email.AddCCRecipient(recipient) - assert.Contains(t, email.CC, recipient) + assert.Contains(t, email.cc, recipient) }) t.Run("AddBCCRecipient", func(t *testing.T) { recipient := "newbcc@example.com" email.AddBCCRecipient(recipient) - assert.Contains(t, email.BCC, recipient) + assert.Contains(t, email.bcc, recipient) }) } @@ -439,7 +367,7 @@ func TestAddsEmailMessageToNils(t *testing.T) { subject := "Subject" text := "Text body" html := "

HTML body

" - attachment := Attachment{Filename: "test.txt", Content: []byte("test content")} + attachment := Attachment{filename: "test.txt", content: []byte("test content")} email := NewFullEmailMessage(from, nil, subject, nil, nil, replyTo, text, html, nil) email.AddToRecipient(to) @@ -447,43 +375,21 @@ func TestAddsEmailMessageToNils(t *testing.T) { email.AddBCCRecipient(bcc) email.AddAttachment(attachment) - assert.Equal(t, from, email.From) - assert.Equal(t, []string{to}, email.To) - assert.Equal(t, []string{cc}, email.CC) - assert.Equal(t, []string{bcc}, email.BCC) - assert.Equal(t, replyTo, email.ReplyTo) - assert.Equal(t, subject, email.Subject) - assert.Equal(t, text, email.Text) - assert.Equal(t, html, email.HTML) - assert.Equal(t, []Attachment{attachment}, email.Attachments) - }) -} - -func TestAttachmentGetters(t *testing.T) { - t.Run("GetFilename", func(t *testing.T) { - attachment := Attachment{Filename: "test.txt"} - assert.Equal(t, "test.txt", attachment.GetFilename()) - assert.Equal(t, "nil_attachment", (*Attachment)(nil).GetFilename()) - }) - - t.Run("GetBase64Content", func(t *testing.T) { - attachment := Attachment{Filename: "test.txt", Content: []byte("hello")} - expected := []byte(base64.StdEncoding.EncodeToString([]byte("hello"))) - assert.Equal(t, expected, attachment.GetBase64Content()) - assert.Equal(t, []byte{}, (*Attachment)(nil).GetBase64Content()) - }) - - t.Run("GetRawContent", func(t *testing.T) { - attachment := Attachment{Filename: "test.txt", Content: []byte("hello")} - expected := []byte("hello") - assert.Equal(t, expected, attachment.GetRawContent()) - assert.Equal(t, []byte{}, (*Attachment)(nil).GetRawContent()) + assert.Equal(t, from, email.from) + assert.Equal(t, []string{to}, email.to) + assert.Equal(t, []string{cc}, email.cc) + assert.Equal(t, []string{bcc}, email.bcc) + assert.Equal(t, replyTo, email.replyTo) + assert.Equal(t, subject, email.subject) + assert.Equal(t, text, email.text) + assert.Equal(t, html, email.html) + assert.Equal(t, []Attachment{attachment}, email.attachments) }) } func TestEmailHTMLBodySanitizers(t *testing.T) { message := EmailMessage{ - HTML: `
XSS
`, + html: `
XSS
`, } t.Run("remove potential XSS attack", func(t *testing.T) { @@ -493,7 +399,7 @@ func TestEmailHTMLBodySanitizers(t *testing.T) { }) message2 := EmailMessage{ - HTML: `Google`, + html: `Google`, } t.Run("on methods not allowed", func(t *testing.T) { @@ -503,7 +409,7 @@ func TestEmailHTMLBodySanitizers(t *testing.T) { }) message3 := EmailMessage{ - HTML: `

Google

`, + html: `

Google

`, } t.Run("

can't have href", func(t *testing.T) { expected := `

Google

` @@ -512,6 +418,255 @@ func TestEmailHTMLBodySanitizers(t *testing.T) { }) } +func TestMarshalJSONCustom(t *testing.T) { + t.Run("Marshal EmailMessage with attachments", func(t *testing.T) { + email := &EmailMessage{ + from: "sender@example.com", + to: []string{"recipient@example.com"}, + cc: []string{"cc@example.com"}, + bcc: []string{"bcc@example.com"}, + replyTo: "replyto@example.com", + subject: "Subject", + text: "This is the email content.", + html: "

This is the email content.

", + attachments: []Attachment{ + {filename: "attachment1.txt", content: []byte("content1")}, + }, + maxAttachmentSize: 1024, + } + jsonData, err := json.Marshal(email) + assert.Nil(t, err) + expected := `{"from":"sender@example.com","to":["recipient@example.com"],"cc":["cc@example.com"],"bcc":["bcc@example.com"],"replyTo":"replyto@example.com","subject":"Subject","text":"This is the email content.","html":"

This is the email content.

","attachments":[{"filename":"attachment1.txt","content":"Y29udGVudDE="}]}` + assert.JSONEq(t, expected, string(jsonData)) + }) + + t.Run("Marshal EmailMessage without attachments", func(t *testing.T) { + email := &EmailMessage{ + from: "sender@example.com", + to: []string{"recipient@example.com"}, + cc: []string{"cc@example.com"}, + bcc: []string{"bcc@example.com"}, + replyTo: "replyto@example.com", + subject: "Subject", + text: "This is the email content.", + html: "

This is the email content.

", + maxAttachmentSize: 1024, + } + jsonData, err := json.Marshal(email) + assert.Nil(t, err) + expected := `{"from":"sender@example.com","to":["recipient@example.com"],"cc":["cc@example.com"],"bcc":["bcc@example.com"],"replyTo":"replyto@example.com","subject":"Subject","text":"This is the email content.","html":"

This is the email content.

"}` + assert.JSONEq(t, expected, string(jsonData)) + }) +} + +func TestUnmarshalJSONCustom(t *testing.T) { + t.Run("Unmarshal EmailMessage with attachments", func(t *testing.T) { + jsonData := `{ + "from": "sender@example.com", + "to": ["recipient@example.com"], + "cc": ["cc@example.com"], + "bcc": ["bcc@example.com"], + "replyTo": "replyto@example.com", + "subject": "Subject", + "text": "This is the email content.", + "html": "

This is the email content.

", + "attachments": [{"filename": "attachment1.txt", "content": "Y29udGVudDE="}] + }` + var email EmailMessage + err := json.Unmarshal([]byte(jsonData), &email) + assert.Nil(t, err) + assert.Equal(t, "sender@example.com", email.from) + assert.Equal(t, []string{"recipient@example.com"}, email.to) + assert.Equal(t, []string{"cc@example.com"}, email.cc) + assert.Equal(t, []string{"bcc@example.com"}, email.bcc) + assert.Equal(t, "replyto@example.com", email.replyTo) + assert.Equal(t, "Subject", email.subject) + assert.Equal(t, "This is the email content.", email.text) + assert.Equal(t, "

This is the email content.

", email.html) + expectedAttachment := Attachment{filename: "attachment1.txt", content: []byte("content1")} + assert.Equal(t, []Attachment{expectedAttachment}, email.attachments) + }) + + t.Run("Unmarshal EmailMessage without attachments", func(t *testing.T) { + jsonData := `{ + "from": "sender@example.com", + "to": ["recipient@example.com"], + "cc": ["cc@example.com"], + "bcc": ["bcc@example.com"], + "replyTo": "replyto@example.com", + "subject": "Subject", + "text": "This is the email content.", + "html": "

This is the email content.

" + }` + var email EmailMessage + err := json.Unmarshal([]byte(jsonData), &email) + assert.Nil(t, err) + assert.Equal(t, "sender@example.com", email.from) + assert.Equal(t, []string{"recipient@example.com"}, email.to) + assert.Equal(t, []string{"cc@example.com"}, email.cc) + assert.Equal(t, []string{"bcc@example.com"}, email.bcc) + assert.Equal(t, "replyto@example.com", email.replyTo) + assert.Equal(t, "Subject", email.subject) + assert.Equal(t, "This is the email content.", email.text) + assert.Equal(t, "

This is the email content.

", email.html) + assert.Nil(t, email.attachments) + }) +} + +func TestGetBase64Content(t *testing.T) { + tests := []struct { + attachment *Attachment + expected []byte + }{ + {&Attachment{filename: "test.txt", content: []byte("hello")}, []byte(base64.StdEncoding.EncodeToString([]byte("hello")))}, + {&Attachment{filename: "test.txt", content: []byte("")}, []byte{}}, + {&Attachment{filename: "empty.txt", content: nil}, []byte{}}, + } + + for _, test := range tests { + t.Run(test.attachment.GetFilename(), func(t *testing.T) { + result := test.attachment.GetBase64Content() + assert.Equal(t, test.expected, result) + }) + } +} + +func TestGetBase64StringContent(t *testing.T) { + tests := []struct { + attachment *Attachment + expected string + }{ + {&Attachment{filename: "test.txt", content: []byte("hello")}, base64.StdEncoding.EncodeToString([]byte("hello"))}, + {&Attachment{filename: "test.txt", content: []byte("")}, ""}, + {nil, ""}, + } + + for _, test := range tests { + t.Run(test.attachment.GetFilename(), func(t *testing.T) { + result := test.attachment.GetBase64StringContent() + assert.Equal(t, test.expected, result) + }) + } +} + +func TestGetRawContent(t *testing.T) { + tests := []struct { + attachment *Attachment + expected []byte + }{ + {&Attachment{filename: "test.txt", content: []byte("hello")}, []byte("hello")}, + {&Attachment{filename: "test.txt", content: []byte("")}, []byte{}}, + {&Attachment{filename: "empty.txt", content: nil}, []byte{}}, + } + + for _, test := range tests { + t.Run(test.attachment.GetFilename(), func(t *testing.T) { + result := test.attachment.GetRawContent() + assert.Equal(t, test.expected, result) + }) + } +} + +func TestGetMimeType(t *testing.T) { + tests := []struct { + filename string + expected string + }{ + {"document.pdf", "application/pdf"}, + {"image.png", "image/png"}, + {"archive.zip", "application/zip"}, + {"unknownfile.unknown", ""}, + {"text.txt", "text/plain; charset=utf-8"}, + {"no_extension", ""}, + } + + for _, test := range tests { + t.Run(test.filename, func(t *testing.T) { + result := GetMimeType(test.filename) + assert.Equal(t, test.expected, result) + }) + } +} + +func TestExtractFilename(t *testing.T) { + t.Run("extract filename from valid path", func(t *testing.T) { + filePath := "/path/to/file/document.pdf" + expected := "document.pdf" + result := extractFilename(filePath) + assert.Equal(t, expected, result) + }) + + t.Run("extract filename from empty path", func(t *testing.T) { + filePath := "" + expected := "" + result := extractFilename(filePath) + assert.Equal(t, expected, result) + }) + + t.Run("extract filename from path with trailing slash", func(t *testing.T) { + filePath := "/path/to/directory/" + expected := "" + result := extractFilename(filePath) + assert.Equal(t, expected, result) + }) +} + +func TestNewAttachmentFromFile(t *testing.T) { + + t.Run("files in test data", func(t *testing.T) { + testFiles := []struct { + filePath string + expectedName string + expectedContent string + }{ + { + filepath.Join("testdata", "testfile.txt"), + "testfile.txt", + `DarkRockMountain +https://darkrockmountain.com/ + +we make it possible + +DarkRockMountain, your trusted partner for developing, implementing, scaling, and maintaining your solutions from concept to production.`, + }, { + filepath.Join("testdata", "testfile.md"), + "testfile.md", + `# DarkRockMountain +**[darkrockmountain.com](https://darkrockmountain.com/)** + +### we make it possible + +DarkRockMountain, your trusted partner for developing, implementing, scaling, and maintaining your solutions from concept to production.`, + }, + } + + for _, testFile := range testFiles { + attachment, err := NewAttachmentFromFile(testFile.filePath) + if err != nil { + t.Fatalf("NewAttachmentFromFile() error = %v, want nil", err) + } + + assert.Equal(t, attachment.filename, testFile.expectedName) + + content, err := os.ReadFile(testFile.filePath) + if err != nil { + t.Fatalf("Failed to read test file: %v", err) + } + assert.Equal(t, string(attachment.content), string(content)) + + } + + }) + + t.Run("file does not exist", func(t *testing.T) { + filePath := "nonexistentfile.txt" + attachment, err := NewAttachmentFromFile(filePath) + assert.NotNil(t, err) + assert.Nil(t, attachment) + }) + +} + func TestSetMaxAttachmentSize(t *testing.T) { email := &EmailMessage{} t.Run("SetMaxAttachmentSize", func(t *testing.T) { @@ -523,16 +678,16 @@ func TestSetMaxAttachmentSize(t *testing.T) { func TestGetAttachmentsWithMaxSize(t *testing.T) { email := &EmailMessage{ - Attachments: []Attachment{ - {Filename: "small.txt", Content: []byte("small content")}, - {Filename: "large.txt", Content: make([]byte, 30*1024*1024)}, // 30 MB + attachments: []Attachment{ + {filename: "small.txt", content: []byte("small content")}, + {filename: "large.txt", content: make([]byte, 30*1024*1024)}, // 30 MB }, maxAttachmentSize: 25 * 1024 * 1024, // 25 MB } t.Run("GetAttachments with size limit", func(t *testing.T) { expected := []Attachment{ - {Filename: "small.txt", Content: []byte("small content")}, + {filename: "small.txt", content: []byte("small content")}, } result := email.GetAttachments() assert.Equal(t, expected, result) @@ -540,8 +695,344 @@ func TestGetAttachmentsWithMaxSize(t *testing.T) { t.Run("GetAttachments with no size limit", func(t *testing.T) { email.SetMaxAttachmentSize(-1) - expected := email.Attachments + expected := email.attachments result := email.GetAttachments() assert.Equal(t, expected, result) }) } + +func TestSetFilename(t *testing.T) { + attachment := &Attachment{} + t.Run("SetFilename", func(t *testing.T) { + expected := "newfile.txt" + attachment.SetFilename(expected) + assert.Equal(t, expected, attachment.filename) + }) +} + +func TestSetContent(t *testing.T) { + attachment := &Attachment{} + t.Run("SetContent", func(t *testing.T) { + expected := []byte("new content") + attachment.SetContent(expected) + assert.Equal(t, expected, attachment.content) + }) +} + +func TestSanitizeInput(t *testing.T) { + t.Run("sanitize input with HTML", func(t *testing.T) { + input := "
Test
" + expected := "<div>Test</div>" + result := SanitizeInput(input) + assert.Equal(t, expected, result) + }) + + t.Run("sanitize input with spaces", func(t *testing.T) { + input := " Test " + expected := "Test" + result := SanitizeInput(input) + assert.Equal(t, expected, result) + }) +} + +func TestGetMimeTypeEdgeCases(t *testing.T) { + t.Run("unknown extension", func(t *testing.T) { + filename := "file.unknownext" + expected := "" + result := GetMimeType(filename) + assert.Equal(t, expected, result) + }) + + t.Run("empty filename", func(t *testing.T) { + filename := "" + expected := "" + result := GetMimeType(filename) + assert.Equal(t, expected, result) + }) +} + +func TestMarshalJSONEdgeCases(t *testing.T) { + t.Run("nil EmailMessage", func(t *testing.T) { + var email *EmailMessage + result, err := json.Marshal(email) + assert.Nil(t, err) + assert.Equal(t, "null", string(result)) + }) + + t.Run("nil Attachment", func(t *testing.T) { + var attachment *Attachment + result, err := json.Marshal(attachment) + assert.Nil(t, err) + assert.Equal(t, "null", string(result)) + }) +} + +func TestUnmarshalJSONEdgeCases(t *testing.T) { + t.Run("empty JSON EmailMessage", func(t *testing.T) { + jsonData := `{}` + var email EmailMessage + err := json.Unmarshal([]byte(jsonData), &email) + assert.Nil(t, err) + assert.Equal(t, "", email.from) + assert.Equal(t, "", email.subject) + assert.Equal(t, "", email.text) + assert.Equal(t, "", email.html) + }) + + t.Run("invalid JSON EmailMessage", func(t *testing.T) { + // Example of JSON data that will cause the unmarshaling to fail + // 'to' should be an array, not a string + invalidJSONData := `{ + "from": "sender@example.com", + "to": "invalid_recipient@example.com", + "cc": ["cc@example.com"], + "bcc": ["bcc@example.com"], + "replyTo": "replyto@example.com", + "subject": "Subject", + "text": "This is the email content.", + "html": "

This is the email content.

", + "attachments": [{"filename": "attachment1.txt", "content": "Y29udGVudDE="}] + }` + + var email EmailMessage + err := json.Unmarshal([]byte(invalidJSONData), &email) + assert.Error(t, err) + }) + + t.Run("invalid JSON Attachment", func(t *testing.T) { + // Example of JSON data that will cause the unmarshaling to fail + // 'filename' should be an string, not an integer + jsonData := `{"filename": 123456789, "content": "invalid_base64"}` + var attachment Attachment + err := json.Unmarshal([]byte(jsonData), &attachment) + assert.Error(t, err) + }) + + t.Run("empty JSON Attachment", func(t *testing.T) { + jsonData := `{}` + var attachment Attachment + err := json.Unmarshal([]byte(jsonData), &attachment) + assert.Nil(t, err) + assert.Equal(t, "", attachment.filename) + assert.Equal(t, []byte{}, attachment.content) + }) + + t.Run("invalid base64 content Attachment", func(t *testing.T) { + jsonData := `{"filename": "file.txt", "content": "invalid_base64"}` + var attachment Attachment + err := json.Unmarshal([]byte(jsonData), &attachment) + assert.NotNil(t, err) + }) + +} + +func TestIsHTMLEdgeCases(t *testing.T) { + t.Run("empty string", func(t *testing.T) { + input := "" + result := isHTML(input) + assert.False(t, result) + }) + + t.Run("string without HTML tags", func(t *testing.T) { + input := "Just a plain text" + result := isHTML(input) + assert.False(t, result) + }) + + t.Run("string with incomplete HTML tag", func(t *testing.T) { + input := "
Test" + result := isHTML(input) + assert.True(t, result) + }) +} + +func TestNewEmailMessageEdgeCases(t *testing.T) { + t.Run("create email with empty body", func(t *testing.T) { + from := "sender@example.com" + to := []string{"recipient@example.com"} + subject := "Subject" + body := "" + email := NewEmailMessage(from, to, subject, body) + + assert.Equal(t, from, email.from) + assert.Equal(t, to, email.to) + assert.Equal(t, subject, email.subject) + assert.Equal(t, body, email.text) + assert.Equal(t, "", email.html) + }) + + t.Run("create email with only spaces in body", func(t *testing.T) { + from := "sender@example.com" + to := []string{"recipient@example.com"} + subject := "Subject" + body := " " + email := NewEmailMessage(from, to, subject, body) + + assert.Equal(t, from, email.from) + assert.Equal(t, to, email.to) + assert.Equal(t, subject, email.subject) + assert.Equal(t, " ", email.text) + assert.Equal(t, "", email.html) + }) +} + +func TestNewFullEmailMessageEdgeCases(t *testing.T) { + t.Run("create full email message with no attachments", func(t *testing.T) { + from := "sender@example.com" + to := []string{"recipient@example.com"} + cc := []string{"cc@example.com"} + bcc := []string{"bcc@example.com"} + replyTo := "replyto@example.com" + subject := "Subject" + text := "Text body" + html := "

HTML body

" + attachments := []Attachment{} + email := NewFullEmailMessage(from, to, subject, cc, bcc, replyTo, text, html, attachments) + + assert.Equal(t, from, email.from) + assert.Equal(t, to, email.to) + assert.Equal(t, cc, email.cc) + assert.Equal(t, bcc, email.bcc) + assert.Equal(t, replyTo, email.replyTo) + assert.Equal(t, subject, email.subject) + assert.Equal(t, text, email.text) + assert.Equal(t, html, email.html) + assert.Equal(t, attachments, email.attachments) + }) + + t.Run("create full email message with empty fields", func(t *testing.T) { + from := "" + to := []string{} + cc := []string{} + bcc := []string{} + replyTo := "" + subject := "" + text := "" + html := "" + attachments := []Attachment{} + email := NewFullEmailMessage(from, to, subject, cc, bcc, replyTo, text, html, attachments) + + assert.Equal(t, from, email.from) + assert.Equal(t, to, email.to) + assert.Equal(t, cc, email.cc) + assert.Equal(t, bcc, email.bcc) + assert.Equal(t, replyTo, email.replyTo) + assert.Equal(t, subject, email.subject) + assert.Equal(t, text, email.text) + assert.Equal(t, html, email.html) + assert.Equal(t, attachments, email.attachments) + }) +} + +func TestAddToRecipientEdgeCases(t *testing.T) { + t.Run("Add multiple recipients", func(t *testing.T) { + email := &EmailMessage{} + recipients := []string{"recipient1@example.com", "recipient2@example.com", "recipient3@example.com"} + for _, recipient := range recipients { + email.AddToRecipient(recipient) + } + assert.Equal(t, recipients, email.to) + }) + + t.Run("Add recipient to nil EmailMessage", func(t *testing.T) { + var email *EmailMessage + assert.Panics(t, func() { email.AddToRecipient("recipient@example.com") }) + }) +} + +func TestSetCCEdgeCases(t *testing.T) { + t.Run("SetCC with empty slice", func(t *testing.T) { + email := &EmailMessage{} + expected := []string{} + email.SetCC(expected) + assert.Equal(t, expected, email.cc) + }) +} + +func TestSetBCCEdgeCases(t *testing.T) { + t.Run("SetBCC with empty slice", func(t *testing.T) { + email := &EmailMessage{} + expected := []string{} + email.SetBCC(expected) + assert.Equal(t, expected, email.bcc) + }) +} + +func TestIsHTML(t *testing.T) { + tests := []struct { + input string + expected bool + }{ + {"Hello", true}, + {"Just a plain text", false}, + {"
HTML content
", true}, + {"Plain text with tag", true}, + } + + for _, test := range tests { + result := isHTML(test.input) + if result != test.expected { + t.Errorf("isHTML(%q) = %v; want %v", test.input, result, test.expected) + } + } +} + +func TestAttachmentGetters(t *testing.T) { + t.Run("GetFilename", func(t *testing.T) { + attachment := Attachment{filename: "test.txt"} + assert.Equal(t, "test.txt", attachment.GetFilename()) + assert.Equal(t, "nil_attachment", (*Attachment)(nil).GetFilename()) + }) + + t.Run("GetBase64Content", func(t *testing.T) { + attachment := Attachment{filename: "test.txt", content: []byte("hello")} + expected := []byte(base64.StdEncoding.EncodeToString([]byte("hello"))) + assert.Equal(t, expected, attachment.GetBase64Content()) + assert.Equal(t, []byte{}, (*Attachment)(nil).GetBase64Content()) + }) + + t.Run("GetRawContent", func(t *testing.T) { + attachment := Attachment{filename: "test.txt", content: []byte("hello")} + expected := []byte("hello") + assert.Equal(t, expected, attachment.GetRawContent()) + assert.Equal(t, []byte{}, (*Attachment)(nil).GetRawContent()) + }) +} + +func TestNewAttachment(t *testing.T) { + filename := "testfile.txt" + content := []byte("This is a test file content.") + attachment := NewAttachment(filename, content) + + if attachment.filename != filename { + t.Errorf("NewAttachment() = %v; want %v", attachment.filename, filename) + } + + if string(attachment.content) != string(content) { + t.Errorf("NewAttachment() content = %v; want %v", string(attachment.content), string(content)) + } +} + +func TestAttachmentEdgeCases(t *testing.T) { + t.Run("GetBase64Content with nil content", func(t *testing.T) { + attachment := &Attachment{} + assert.Equal(t, []byte{}, attachment.GetBase64Content()) + }) + + t.Run("GetBase64StringContent with nil content", func(t *testing.T) { + attachment := &Attachment{} + assert.Equal(t, "", attachment.GetBase64StringContent()) + }) + + t.Run("SetContent with nil content", func(t *testing.T) { + attachment := &Attachment{} + attachment.SetContent(nil) + assert.Nil(t, attachment.content) + }) + + t.Run("SetFilename with empty string", func(t *testing.T) { + attachment := &Attachment{} + attachment.SetFilename("") + assert.Equal(t, "", attachment.filename) + }) +} diff --git a/go.mod b/go.mod index 76e0ebf..d72d8a7 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/darkrockmountain/gomail -go 1.22.3 +go 1.22.4 require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 diff --git a/providers/helper_functions_test.go b/providers/helper_functions_test.go index 79c1f25..55f625e 100644 --- a/providers/helper_functions_test.go +++ b/providers/helper_functions_test.go @@ -26,9 +26,7 @@ func TestBuildMimeMessage(t *testing.T) { gomail.NewEmailMessage("sender@example.com", []string{"recipient@example.com"}, "Test Email", "This is a test email."). SetCC([]string{"cc@example.com"}). SetBCC([]string{"bcc@example.com"}). - SetAttachments([]gomail.Attachment{ - {Filename: "test.txt", Content: []byte("This is a test attachment.")}, - }), + SetAttachments([]gomail.Attachment{*gomail.NewAttachment("test.txt", []byte("This is a test attachment."))}), []string{"From: sender@example.com", "To: recipient@example.com", "Cc: cc@example.com", "Subject: Test Email", "This is a test email.", "Content-Disposition: attachment; filename=\"test.txt\"", base64.StdEncoding.EncodeToString([]byte("This is a test attachment."))}, }, { @@ -41,7 +39,7 @@ func TestBuildMimeMessage(t *testing.T) { } for _, test := range tests { - t.Run(test.message.Subject, func(t *testing.T) { + t.Run(test.message.GetSubject(), func(t *testing.T) { result, err := BuildMimeMessage(test.message) if err != nil { t.Fatalf("unexpected error: %v", err) diff --git a/providers/mailgun/mailgun_email_sender_test.go b/providers/mailgun/mailgun_email_sender_test.go index 1b7a9b0..93d2748 100644 --- a/providers/mailgun/mailgun_email_sender_test.go +++ b/providers/mailgun/mailgun_email_sender_test.go @@ -56,10 +56,7 @@ func TestMailgunEmailSender_SendEmail(t *testing.T) { SetReplyTo("replyto@example.com"). SetHTML("

This is a test email.

"). SetBCC([]string{"bcc@example.com"}). - AddAttachment(gomail.Attachment{ - Filename: "test.txt", - Content: []byte("This is a test attachment."), - }) + AddAttachment(*gomail.NewAttachment("test.txt", []byte("This is a test attachment."))) err := emailSender.SendEmail(message) assert.NoError(t, err) diff --git a/providers/mandrill/mandrill_email_sender_test.go b/providers/mandrill/mandrill_email_sender_test.go index b944560..1048a72 100644 --- a/providers/mandrill/mandrill_email_sender_test.go +++ b/providers/mandrill/mandrill_email_sender_test.go @@ -33,10 +33,7 @@ func TestMandrillEmailSender_SendEmail(t *testing.T) { SetReplyTo("replyto@example.com"). SetHTML("

This is a test email.

"). SetBCC([]string{"bcc@example.com"}). - AddAttachment(gomail.Attachment{ - Filename: "test.txt", - Content: []byte("This is a test attachment."), - }) + AddAttachment(*gomail.NewAttachment("test.txt", []byte("This is a test attachment."))) // Mock server ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/providers/microsoft365/microsoft365_email_sender_test.go b/providers/microsoft365/microsoft365_email_sender_test.go index 58df987..945f707 100644 --- a/providers/microsoft365/microsoft365_email_sender_test.go +++ b/providers/microsoft365/microsoft365_email_sender_test.go @@ -82,10 +82,7 @@ func mockItemSendMailRequestBuild(err error) *users.UserItemRequestBuilder { } func TestSendEmail(t *testing.T) { - attachment := gomail.Attachment{ - Filename: "test.txt", - Content: []byte("test_attachment_content"), - } + attachment := *gomail.NewAttachment("test.txt", []byte("test_attachment_content")) message := gomail.NewEmailMessage( "sender@example.com", @@ -177,10 +174,7 @@ func TestComposeMessage_WithReplyTo(t *testing.T) { func TestComposeMessage_WithAttachments(t *testing.T) { - attachment := gomail.Attachment{ - Filename: "test.txt", - Content: []byte("test_attachment_content"), - } + attachment := *gomail.NewAttachment("test.txt", []byte("test_attachment_content")) message := gomail.NewEmailMessage( "sender@example.com", @@ -259,10 +253,7 @@ func TestNewMSGraphEmailSenderROPC(t *testing.T) { /////////////// func TestSendEmail_NoUserRequestBuilder(t *testing.T) { - attachment := gomail.Attachment{ - Filename: "test.txt", - Content: []byte("test_attachment_content"), - } + attachment := *gomail.NewAttachment("test.txt", []byte("test_attachment_content")) message := gomail.NewEmailMessage( "sender@example.com", @@ -282,10 +273,7 @@ func TestSendEmail_NoUserRequestBuilder(t *testing.T) { func TestComposeMessage_LargeAttachment(t *testing.T) { largeContent := make([]byte, 10*1024*1024) // 10 MB - attachment := gomail.Attachment{ - Filename: "large.txt", - Content: largeContent, - } + attachment := *gomail.NewAttachment("large.txt", largeContent) message := gomail.NewEmailMessage( "sender@example.com", @@ -302,14 +290,8 @@ func TestComposeMessage_LargeAttachment(t *testing.T) { } func TestComposeMessage_MultipleAttachments(t *testing.T) { - attachment1 := gomail.Attachment{ - Filename: "test1.txt", - Content: []byte("test_attachment_content1"), - } - attachment2 := gomail.Attachment{ - Filename: "test2.txt", - Content: []byte("test_attachment_content2"), - } + attachment1 := *gomail.NewAttachment("test1.txt", []byte("test_attachment_content1")) + attachment2 := *gomail.NewAttachment("test2.txt", []byte("test_attachment_content2")) message := gomail.NewEmailMessage( "sender@example.com", @@ -347,10 +329,7 @@ func TestComposeMessage_MissingFields(t *testing.T) { } func TestSendEmail_FailedSend(t *testing.T) { - attachment := gomail.Attachment{ - Filename: "test.txt", - Content: []byte("test_attachment_content"), - } + attachment := *gomail.NewAttachment("test.txt", []byte("test_attachment_content")) message := gomail.NewEmailMessage( "sender@example.com", diff --git a/providers/postmark/postmark_email_sender_test.go b/providers/postmark/postmark_email_sender_test.go index b9181df..2d042d0 100644 --- a/providers/postmark/postmark_email_sender_test.go +++ b/providers/postmark/postmark_email_sender_test.go @@ -34,10 +34,7 @@ func TestPostmarkEmailSender_SendEmail(t *testing.T) { SetReplyTo("replyto@example.com"). SetHTML("

This is a test email.

"). SetBCC([]string{"bcc@example.com"}). - AddAttachment(gomail.Attachment{ - Filename: "test.txt", - Content: []byte("This is a test attachment."), - }) + AddAttachment(*gomail.NewAttachment("test.txt", []byte("This is a test attachment."))) // Mock server ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { diff --git a/providers/sendgrid/sendgrid_email_sender_test.go b/providers/sendgrid/sendgrid_email_sender_test.go index b7ad6c7..2861c5f 100644 --- a/providers/sendgrid/sendgrid_email_sender_test.go +++ b/providers/sendgrid/sendgrid_email_sender_test.go @@ -66,10 +66,7 @@ func TestSendGridEmailSender_SendEmail(t *testing.T) { SetReplyTo("replyto@example.com"). SetHTML("

This is a test email.

"). SetBCC([]string{"bcc@example.com"}). - AddAttachment(gomail.Attachment{ - Filename: "test.txt", - Content: []byte("This is a test attachment."), - }) + AddAttachment(*gomail.NewAttachment("test.txt", []byte("This is a test attachment."))) err := emailSender.SendEmail(message) assert.NoError(t, err) @@ -132,10 +129,7 @@ func TestSendGridEmailSender_SendEmailWithAttachments(t *testing.T) { []string{"recipient@example.com"}, "Test Subject", "Test Body", - ).AddAttachment(gomail.Attachment{ - Filename: "test.txt", - Content: []byte(attachmentContent), - }) + ).AddAttachment(*gomail.NewAttachment("test.txt", []byte(attachmentContent))) err := emailSender.SendEmail(message) assert.NoError(t, err) @@ -149,5 +143,5 @@ func TestSendGridEmailSender_SendEmailWithAttachments(t *testing.T) { attachment.SetDisposition("attachment") v3Mail.AddAttachment(attachment) - assert.Equal(t, v3Mail.Attachments[0].Content, message.Attachments[0].GetBase64StringContent()) + assert.Equal(t, v3Mail.Attachments[0].Content, message.GetAttachments()[0].GetBase64StringContent()) } diff --git a/providers/ses/ses_email_sender_test.go b/providers/ses/ses_email_sender_test.go index ca7dbd8..c7892b6 100644 --- a/providers/ses/ses_email_sender_test.go +++ b/providers/ses/ses_email_sender_test.go @@ -136,10 +136,7 @@ func TestSESEmailSender_SendEmailWithAttachments(t *testing.T) { []string{"recipient@example.com"}, "Test Subject", "Test Body", - ).AddAttachment(gomail.Attachment{ - Filename: "test.txt", - Content: []byte("This is a test attachment."), - }) + ).AddAttachment(*gomail.NewAttachment("test.txt", []byte("This is a test attachment."))) err := emailSender.SendEmail(message) assert.NoError(t, err) diff --git a/providers/sparkpost/sparkpost_email_sender_test.go b/providers/sparkpost/sparkpost_email_sender_test.go index a933ca5..9560334 100644 --- a/providers/sparkpost/sparkpost_email_sender_test.go +++ b/providers/sparkpost/sparkpost_email_sender_test.go @@ -85,10 +85,7 @@ func TestSparkPostEmailSender_SendEmail(t *testing.T) { SetReplyTo("replyto@example.com"). SetHTML("

This is a test email.

"). SetBCC([]string{"bcc@example.com"}). - AddAttachment(gomail.Attachment{ - Filename: "test.txt", - Content: []byte("This is a test attachment."), - }) + AddAttachment(*gomail.NewAttachment("test.txt", []byte("This is a test attachment."))) err := emailSender.SendEmail(message) assert.NoError(t, err) @@ -159,10 +156,7 @@ func TestSparkPostEmailSender_SendEmailWithAttachments(t *testing.T) { []string{"recipient@example.com"}, "Test Email", "This is a test email.", - ).AddAttachment(gomail.Attachment{ - Filename: "test.txt", - Content: []byte("This is a test attachment."), - }) + ).AddAttachment(*gomail.NewAttachment("test.txt", []byte("This is a test attachment."))) err := emailSender.SendEmail(message) assert.NoError(t, err) diff --git a/testdata/darkrockmountain-logo.png b/testdata/darkrockmountain-logo.png new file mode 100644 index 0000000..1a3a142 Binary files /dev/null and b/testdata/darkrockmountain-logo.png differ diff --git a/testdata/testfile.md b/testdata/testfile.md new file mode 100644 index 0000000..1fcb1db --- /dev/null +++ b/testdata/testfile.md @@ -0,0 +1,6 @@ +# DarkRockMountain +**[darkrockmountain.com](https://darkrockmountain.com/)** + +### we make it possible + +DarkRockMountain, your trusted partner for developing, implementing, scaling, and maintaining your solutions from concept to production. \ No newline at end of file diff --git a/testdata/testfile.txt b/testdata/testfile.txt new file mode 100644 index 0000000..7754d31 --- /dev/null +++ b/testdata/testfile.txt @@ -0,0 +1,6 @@ +DarkRockMountain +https://darkrockmountain.com/ + +we make it possible + +DarkRockMountain, your trusted partner for developing, implementing, scaling, and maintaining your solutions from concept to production. \ No newline at end of file