Skip to content

feat(email): integrate mailtrap provider#114

Merged
Cysteine12 merged 7 commits intodevelopfrom
feature/integrate-mailtrap-provider
Feb 19, 2026
Merged

feat(email): integrate mailtrap provider#114
Cysteine12 merged 7 commits intodevelopfrom
feature/integrate-mailtrap-provider

Conversation

@Cysteine12
Copy link
Owner

@Cysteine12 Cysteine12 commented Feb 19, 2026

What was changed

  • restructure email infra
  • docker-compose
  • all app properties files

Why it was changed

  • allow easy switch between email providers, from ses to mailtrap

How it was implemented

  • used strategy pattern via an EmailProvider interface.
  • move related email management to infra

Linked Issue

Closes #112

Summary by CodeRabbit

  • New Features

    • Selectable email providers (SES or Mailtrap) with Mailtrap SMTP support and configurable sender address.
  • Improvements

    • Unified, pluggable email delivery used across the app.
    • Email failures now return a clear 503 Service Unavailable response with error code "EMAIL_FAILED".
  • Chores

    • Added mail runtime support, new mail-related config keys and environment variables, test config updates, and a dedicated email-sending exception.

@Cysteine12 Cysteine12 self-assigned this Feb 19, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉


📝 Walkthrough

Walkthrough

Adds a pluggable email subsystem: provider interface and SES/Mailtrap implementations, Mailtrap SMTP configuration, AppProperties email settings and validation, spring mail dependency, EmailService refactor to use providers, new EmailSendingException and specific handler, and environment/property/docker-compose updates for Mailtrap.

Changes

Cohort / File(s) Summary
Email provider abstraction & implementations
server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/EmailProvider.java, server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/MailtrapEmailProvider.java, server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/SesEmailProvider.java
Added EmailProvider interface and SES/Mailtrap implementations. Both expose send(to, subject, body) and wrap failures with EmailSendingException.
Email service & consumers
server/src/main/java/org/eni/koinoniadaily/infrastructure/email/EmailService.java, server/src/main/java/org/eni/koinoniadaily/modules/auth/AuthEventListener.java
Refactored EmailService to depend on EmailProvider (replaced direct SES client); updated import in AuthEventListener.
Configuration classes
server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/MailtrapConfig.java, server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/SesConfig.java
Added MailtrapConfig to expose JavaMailSender when app.email.provider=mailtrap. Moved SesConfig and added @ConditionalOnProperty so it loads only for provider=ses (default when missing).
App properties & validation
server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java
Added @Validated, new nested Email and Mailtrap classes with validation annotations and fields; removed sesFromEmail from Aws.
Dependency & mail defaults
server/pom.xml, server/src/main/resources/application.properties
Added spring-boot-starter-mail dependency and default Mailtrap SMTP host/port properties.
Properties, compose & env
server/docker-compose.yml, server/src/main/resources/application-dev.properties, server/src/main/resources/application-prod.properties, server/src/test/resources/application-test.properties
Introduced app.email.provider, app.email.from, and app.mailtrap.* properties across environments; removed app.aws.ses-from-email; added docker-compose env vars for Mailtrap credentials.
Exception handling
server/src/main/java/org/eni/koinoniadaily/exceptions/EmailSendingException.java, server/src/main/java/org/eni/koinoniadaily/exceptions/GlobalExceptionHandler.java
Added EmailSendingException and a handler returning 503 with error code EMAIL_FAILED.
Schema & tests
server/src/main/resources/schema.sql, server/src/test/resources/application-test.properties
Removed multiple DDL statements from schema.sql; test properties updated to use test DB and new email settings.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant EmailSvc as EmailService
    participant Provider as EmailProvider
    participant SES as AWS SES
    participant SMTP as Mailtrap SMTP

    App->>EmailSvc: request sendEmail(to, subject, template)
    EmailSvc->>Provider: render template -> send(to, subject, body)
    alt provider = ses
        Provider->>SES: SendEmailRequest(source, dest, message)
        SES-->>Provider: SendEmailResponse
    else provider = mailtrap
        Provider->>SMTP: SMTP connect/auth, send MIME HTML
        SMTP-->>Provider: 250 OK / success
    end
    Provider-->>EmailSvc: success or throws EmailSendingException
    EmailSvc-->>App: return or propagate exception
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐇 I stitched a provider, nimble and bright,
SES by day and Mailtrap at night,
Templates glow, headers hum,
Rabbit hops — the emails come,
Hop, send, and rest till morning light ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(email): integrate mailtrap provider' clearly and concisely summarizes the main change: adding Mailtrap as an email provider integration.
Linked Issues check ✅ Passed All requirements from issue #112 are met: spring-boot-starter-mail dependency added, infrastructure folder created with EmailService, EmailProvider interface, SesEmailProvider and MailtrapEmailProvider implementations, and SesConfig/MailtrapConfig configurations.
Out of Scope Changes check ✅ Passed All changes align with the stated objective of integrating Mailtrap provider and restructuring email infrastructure; no extraneous modifications were introduced.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)

✅ Unit Test PR creation complete.

  • Create PR with unit tests
  • Commit unit tests in branch feature/integrate-mailtrap-provider
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Cysteine12 Cysteine12 added enhancement New feature or request dependencies server Changes involving server application labels Feb 19, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Cysteine12, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the application's email sending capabilities by introducing a flexible, provider-agnostic architecture. It refactors the existing email service to utilize a strategy pattern, enabling seamless switching between different email providers. The initial implementation integrates Mailtrap as a new provider, alongside the existing AWS SES, and updates configuration files across the application to support this modular approach.

Highlights

  • Email Provider Strategy Pattern: Implemented a strategy pattern for email providers, allowing the application to easily switch between different email sending services like AWS SES and Mailtrap.
  • Mailtrap Integration: Integrated Mailtrap as a new email sending option, providing an alternative to AWS SES.
  • Email Infrastructure Refactoring: Refactored the email infrastructure by moving related classes to a dedicated 'infrastructure.email' package for better organization and modularity.
  • Configuration Updates: Updated application properties, Docker Compose, and POM file to support the new modular email provider setup and Mailtrap integration.
  • Schema File Removal: Removed the 'schema.sql' file, which contained outdated test table definitions.
Changelog
  • server/docker-compose.yml
    • Added 'APP_EMAIL_PROVIDER', 'APP_EMAIL_FROM', and 'APP_MAILTRAP_PASSWORD' environment variables.
    • Removed 'AWS_SES_FROM_EMAIL' environment variable.
  • server/pom.xml
    • Added 'spring-boot-starter-mail' dependency for JavaMailSender.
  • server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java
    • Introduced '@validated' annotation for property validation.
    • Added nested 'Email' and 'Mailtrap' property classes for email configuration.
    • Removed 'sesFromEmail' from 'Aws' properties.
  • server/src/main/java/org/eni/koinoniadaily/infrastructure/email/EmailService.java
    • Renamed the file and package from 'services' to 'infrastructure.email'.
    • Refactored to depend on the 'EmailProvider' interface instead of 'SesClient'.
    • Removed the internal 'sendEmail' private method.
  • server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/MailtrapConfig.java
    • Added a new configuration class to set up 'JavaMailSender' for Mailtrap, activated conditionally.
  • server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/SesConfig.java
    • Renamed the file and package from 'config' to 'infrastructure.email.config'.
    • Applied '@ConditionalOnProperty' to activate only when 'app.email.provider' is 'ses' or missing.
  • server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/EmailProvider.java
    • Added a new interface defining the 'send' method for email providers.
  • server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/MailtrapEmailProvider.java
    • Added a new component implementing 'EmailProvider' for sending emails via Mailtrap using 'JavaMailSender'.
  • server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/SesEmailProvider.java
    • Added a new component implementing 'EmailProvider' for sending emails via AWS SES using 'SesClient'.
  • server/src/main/java/org/eni/koinoniadaily/modules/auth/AuthEventListener.java
    • Updated the import statement for 'EmailService' to reflect its new package location.
  • server/src/main/resources/application-dev.properties
    • Configured 'app.email.provider' to 'mailtrap'.
    • Added commented placeholders for new email properties ('app.email.from', 'app.mailtrap.password').
  • server/src/main/resources/application-prod.properties
    • Configured environment variable mappings for 'app.email.provider', 'app.email.from', and 'app.mailtrap.password'.
    • Removed 'app.aws.ses-from-email' property.
  • server/src/main/resources/application.properties
    • Added default Mailtrap host, port, and username properties.
  • server/src/main/resources/schema.sql
    • Removed the 'schema.sql' file.
  • server/src/test/resources/application-test.properties
    • Updated the 'spring.datasource.url' to use a dedicated test database.
    • Added 'app.email.from' and 'app.mailtrap.password' properties.
Activity
  • No specific activity has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@Cysteine12 Cysteine12 changed the title fix(email): integrate mailtrap provider feat(email): integrate mailtrap provider Feb 19, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request does an excellent job of refactoring the email sending functionality to support multiple providers using the Strategy pattern. The code is well-structured, with email-related components correctly moved to the infrastructure.email package. The use of @ConditionalOnProperty for provider selection is a good approach, and the configuration properties are well-organized and validated. I have a couple of minor suggestions to enhance error logging for better debuggability. Overall, this is a great architectural improvement.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (2)
server/docker-compose.yml (1)

17-19: Externalize Mailtrap SMTP host and port as environment variables for consistency.

The Mailtrap host (live.smtp.mailtrap.io) and port (587) are hardcoded in application.properties (lines 11-12), while other Mailtrap configuration like password, provider, and email-from are externalized as environment variables in production (application-prod.properties). Hardcoding these values forces code changes if endpoints differ between deployment environments. Adding APP_MAILTRAP_HOST and APP_MAILTRAP_PORT to the docker-compose file keeps all environment configuration centralized, consistent with the existing pattern.

♻️ Proposed addition
      - APP_MAILTRAP_USERNAME=${APP_MAILTRAP_USERNAME}
      - APP_MAILTRAP_PASSWORD=${APP_MAILTRAP_PASSWORD}
+     - APP_MAILTRAP_HOST=${APP_MAILTRAP_HOST}
+     - APP_MAILTRAP_PORT=${APP_MAILTRAP_PORT}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/docker-compose.yml` around lines 17 - 19, The Mailtrap SMTP host and
port are hardcoded in application.properties while other Mail settings are
pulled from env vars; add APP_MAILTRAP_HOST and APP_MAILTRAP_PORT to the service
environment block alongside
APP_EMAIL_PROVIDER/APP_EMAIL_FROM/APP_MAILTRAP_PASSWORD in docker-compose.yml so
these values are externalized, and update application.properties to reference
${APP_MAILTRAP_HOST} and ${APP_MAILTRAP_PORT} instead of the literal
"live.smtp.mailtrap.io" and "587".
server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/MailtrapConfig.java (1)

31-34: mail.debug is hardcoded and mail.smtp.starttls.required is absent.

Two minor hardening notes:

  1. mail.debug=false is hardcoded — there's no way to enable verbose JavaMail tracing for dev debugging without a code change. Consider externalizing it:
javaMailProperties.put("mail.debug", String.valueOf(props.getMailtrap().isDebug()));

or simply bind it to a spring.mail.debug compatible property.

  1. mail.smtp.starttls.required is not setstarttls.enable=true offers STARTTLS but doesn't enforce it; a MITM or misconfigured server could negotiate a plaintext session. For Mailtrap live SMTP (port 587), add:
🔒 Proposed fix
 javaMailProperties.put("mail.smtp.starttls.enable", "true");
+javaMailProperties.put("mail.smtp.starttls.required", "true");
 javaMailProperties.put("mail.debug", "false");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/MailtrapConfig.java`
around lines 31 - 34, In MailtrapConfig, externalize the hardcoded mail.debug
and enforce STARTTLS: read the debug flag from the mail properties (e.g.,
props.getMailtrap().isDebug() or spring.mail.debug equivalent) and set
javaMailProperties "mail.debug" using that value instead of "false";
additionally add the "mail.smtp.starttls.required" property (set to true for
Mailtrap on 587) alongside "mail.smtp.starttls.enable" to require TLS
negotiation. Update the javaMailProperties handling in the MailtrapConfig class
so both "mail.debug" and "mail.smtp.starttls.required" are set from
configuration/constant rather than hardcoded.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/docker-compose.yml`:
- Around line 17-19: Add the missing Mailtrap username env var: update
docker-compose.yml to expose APP_MAILTRAP_USERNAME as an environment variable
(e.g., add - APP_MAILTRAP_USERNAME=${APP_MAILTRAP_USERNAME}); remove the
hardcoded username in server/src/main/resources/application.properties (replace
app.mailtrap.username=api with a placeholder reference
app.mailtrap.username=${APP_MAILTRAP_USERNAME}); and ensure
server/src/main/resources/application-prod.properties includes
app.mailtrap.username=${APP_MAILTRAP_USERNAME} so both username and password are
parameterized consistently.

In `@server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java`:
- Line 14: AppProperties currently applies `@Validated` but lacks proper
cascading: add `@Valid` to the email and aws fields in AppProperties (so nested
Email and Aws constraints are enforced) but do NOT add `@Valid` to the Mailtrap
field; remove/stop using JSR-303 constraints on the Mailtrap class and instead
add a runtime check in MailtrapConfig (or a `@PostConstruct` method) that reads
AppProperties.getEmail().getProvider() and only when it equals "mailtrap" assert
the Mailtrap properties (host, username, password non-blank and port > 0) to
fail startup if Mailtrap is required.

In
`@server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/SesConfig.java`:
- Line 15: Remove matchIfMissing = true from the `@ConditionalOnProperty`
annotations on SesConfig and SesEmailProvider so SES is not activated by absence
of the property; instead add matchIfMissing = true to the `@ConditionalOnProperty`
annotations on MailtrapConfig and MailtrapEmailProvider to make Mailtrap the
default; ensure AppProperties.Email.provider’s default ("mailtrap") now matches
these annotation changes so the active provider selection is consistent.

In
`@server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/EmailProvider.java`:
- Line 4: The EmailProvider interface method declaration "void send (String to,
String subject, String body);" contains a space before the opening parenthesis
which violates MethodParamPad; remove the space so the signature reads "void
send(String to, String subject, String body)". Also restore or add the missing
google_checks.xml referenced by the build (or add the appropriate Checkstyle
dependency that provides the Google configuration) so checkstyle can run; ensure
the file is placed where the pom expects it (or update pom to point to the
provided config) so the verify phase does not fail.

In
`@server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/MailtrapEmailProvider.java`:
- Around line 38-40: In MailtrapEmailProvider's catch block (the one catching
MessagingException | MailException) fix the truncated log message by either
removing the dangling "to" or appending a safe recipient indicator: update
log.error(...) to log a descriptive message plus either a masked recipient
(derive from the outgoing message/recipient list in this class, e.g., mask
local-part of the address) or a non-PII summary like "recipient redacted" or
"recipientCount=X"; also adjust the thrown RuntimeException message to match
(e.g., "Failed to send email via Mailtrap" or include the same safe recipient
summary) so logs are clear and do not leak PII.

In `@server/src/main/resources/application-prod.properties`:
- Around line 16-18: The app.mailtrap.password property in
application-prod.properties is unguarded and maps to ${APP_MAILTRAP_PASSWORD}
which causes startup failure for SES-only deployments; change the property to
include a colon-default (e.g. ${APP_MAILTRAP_PASSWORD:}) so it is optional, and
modify the AppProperties.Mailtrap.password field (currently annotated with
`@NotBlank`) to avoid unconditional validation—either remove `@NotBlank`, make the
field nullable with a default, or implement conditional validation (custom
validator or validation groups) so `@NotBlank` is only enforced when
AppProperties.email.provider == "mailtrap".

In `@server/src/test/resources/application-test.properties`:
- Around line 27-29: Add the missing app.email.provider property to the test
properties so MailtrapConfig is activated during tests: set
app.email.provider=mailtrap in the test config (since SesConfig uses
matchIfMissing=true and will otherwise be chosen), ensuring MailtrapConfig picks
up the provided app.mailtrap.password and app.email.from for the test context.

---

Duplicate comments:
In `@server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java`:
- Around line 33-40: The Email.provider field currently has a Java default
("mailtrap") which does not affect `@ConditionalOnProperty` checks (used in
SesConfig); remove the in-code default from the Email class (private String
provider;) or alternatively ensure app.email.provider is explicitly defined in
all property sources (application*.yml/properties) and adjust the
`@ConditionalOnProperty` havingValue in SesConfig to match the intended provider
name so conditional beans behave predictably.

In
`@server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/SesEmailProvider.java`:
- Line 19: The ConditionalOnProperty on SesEmailProvider is inconsistent with
SesConfig's default; update the `@ConditionalOnProperty`(name =
"app.email.provider", havingValue = "ses", matchIfMissing = /* true|false */) in
the SesEmailProvider class so its matchIfMissing value exactly matches the one
used on SesConfig (i.e., pick the same boolean default strategy you chose) to
keep activation behavior consistent.

---

Nitpick comments:
In `@server/docker-compose.yml`:
- Around line 17-19: The Mailtrap SMTP host and port are hardcoded in
application.properties while other Mail settings are pulled from env vars; add
APP_MAILTRAP_HOST and APP_MAILTRAP_PORT to the service environment block
alongside APP_EMAIL_PROVIDER/APP_EMAIL_FROM/APP_MAILTRAP_PASSWORD in
docker-compose.yml so these values are externalized, and update
application.properties to reference ${APP_MAILTRAP_HOST} and
${APP_MAILTRAP_PORT} instead of the literal "live.smtp.mailtrap.io" and "587".

In
`@server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/MailtrapConfig.java`:
- Around line 31-34: In MailtrapConfig, externalize the hardcoded mail.debug and
enforce STARTTLS: read the debug flag from the mail properties (e.g.,
props.getMailtrap().isDebug() or spring.mail.debug equivalent) and set
javaMailProperties "mail.debug" using that value instead of "false";
additionally add the "mail.smtp.starttls.required" property (set to true for
Mailtrap on 587) alongside "mail.smtp.starttls.enable" to require TLS
negotiation. Update the javaMailProperties handling in the MailtrapConfig class
so both "mail.debug" and "mail.smtp.starttls.required" are set from
configuration/constant rather than hardcoded.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
server/src/main/java/org/eni/koinoniadaily/exceptions/EmailSendingException.java (1)

1-12: LGTM — clean, minimal exception class consistent with the codebase pattern.

(String message, Throwable cause) constructor is valuable here since it preserves the root cause (MessagingException, MailException, etc.) when wrapping, which aids debugging.

As an optional nit: RuntimeException implements Serializable, so declaring private static final long serialVersionUID = 1L; suppresses the implicit serialVersionUID compiler warning and is idiomatic for custom exception types.

♻️ Add serialVersionUID
 public class EmailSendingException extends RuntimeException {
+  private static final long serialVersionUID = 1L;
+
   public EmailSendingException(String message) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@server/src/main/java/org/eni/koinoniadaily/exceptions/EmailSendingException.java`
around lines 1 - 12, Add a serialVersionUID to the EmailSendingException class
to suppress the implicit serialVersionUID warning and follow the idiom for
serializable exceptions: declare a private static final long serialVersionUID =
1L; inside the EmailSendingException class (which already defines the two
constructors EmailSendingException(String) and EmailSendingException(String,
Throwable)) so the class explicitly defines its serialization identifier.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@server/src/main/java/org/eni/koinoniadaily/exceptions/EmailSendingException.java`:
- Around line 1-12: Add a serialVersionUID to the EmailSendingException class to
suppress the implicit serialVersionUID warning and follow the idiom for
serializable exceptions: declare a private static final long serialVersionUID =
1L; inside the EmailSendingException class (which already defines the two
constructors EmailSendingException(String) and EmailSendingException(String,
Throwable)) so the class explicitly defines its serialization identifier.

@Cysteine12
Copy link
Owner Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively refactors the email sending functionality to support multiple providers using a Strategy pattern. The introduction of an EmailProvider interface and its SES and Mailtrap implementations is well-executed, improving modularity and making it easy to switch between providers. The configuration properties have been reorganized logically, and a new exception handler for email sending failures improves error handling. The changes are clean and well-implemented. I have one minor suggestion to correct a typo in a standard field name.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java (2)

35-41: No validation on provider value — typos cause a confusing startup failure.

If app.email.provider is set to an invalid value (e.g., "mailtraap"), neither SesConfig nor MailtrapConfig activates, and the missing EmailProvider bean produces a cryptic NoSuchBeanDefinitionException. Consider constraining the value with @Pattern:

Proposed fix
   public static class Email {

+    `@Pattern`(regexp = "ses|mailtrap", message = "Email provider must be 'ses' or 'mailtrap'")
     private String provider = "ses";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java` around
lines 35 - 41, Add validation on the Email.provider field to fail-fast on typos:
annotate the provider field in the nested AppProperties.Email class with a
constraint such as `@Pattern`(regexp = "^(ses|mailtrap)$", message = "Invalid
email provider, must be 'ses' or 'mailtrap'") (or an equivalent annotation) so
Spring’s configuration binding validates that provider is one of the supported
values and produces a clear error instead of a NoSuchBeanDefinitionException for
EmailProvider.

34-35: @Validated on nested static classes is ineffective.

@Validated is meaningful on Spring-managed beans (e.g., @ConfigurationProperties, @Controller). On plain nested static classes, it has no effect — validation cascading is controlled solely by @Valid on the parent field. These annotations are misleading and can be removed.

Proposed cleanup
   `@Data`
-  `@Validated`
   public static class Email {
   `@Data`
-  `@Validated`
   public static class Aws {
   `@Data`
-  `@Validated`
   public static class Mailtrap {

Also applies to: 44-45, 60-62

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java` around
lines 34 - 35, Remove the ineffective `@Validated` annotations from the nested
static configuration classes (e.g., the Email class and the other nested static
classes referenced around lines 44-45 and 60-62) because `@Validated` only works
on Spring-managed beans; instead ensure validation is triggered via `@Valid` on
the parent property that binds the ConfigurationProperties. Locate the nested
static classes (such as Email) in AppProperties and delete their `@Validated`
annotations, and confirm the parent field that holds these nested types is
annotated with `@Valid` so validation still cascades.
server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/MailtrapConfig.java (1)

35-35: Consider making mail.debug configurable rather than hardcoded to false.

Tying this to a property or the active Spring profile (e.g., true in dev) would help troubleshoot SMTP issues without code changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/MailtrapConfig.java`
at line 35, In MailtrapConfig.java the javaMailProperties currently hardcodes
javaMailProperties.put("mail.debug", "false"); — make this value configurable by
reading a property (e.g., from Environment or `@Value`) or by checking the active
Spring profile in the MailtrapConfig class; replace the hardcoded "false" with
the fetched property (for example a key like spring.mail.properties.mail.debug
or a custom mail.debug property) so devs can enable debug in dev without code
changes and keep it off in prod.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@server/src/main/java/org/eni/koinoniadaily/exceptions/EmailSendingException.java`:
- Line 5: The class EmailSendingException defines a wrongly named serialization
field serialVersionID which the JVM ignores; rename and correct it to the
standard private static final long serialVersionUID = 1L inside
EmailSendingException so the JVM recognizes the explicit serial UID and avoids
automatic synthetic UID computation.

---

Duplicate comments:
In `@server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java`:
- Around line 29-31: Add javax.validation.Valid to the nested properties in
AppProperties so JSR-303 validation cascades: annotate the email and aws fields
with `@Valid` and also annotate mailtrap with `@Valid` if you intend to validate it
normally; then implement conditional validation for Mailtrap in MailtrapConfig
by adding a `@PostConstruct` method (e.g. validateMailtrapProperties) that
retrieves props.getMailtrap() and uses assertions (Assert.hasText /
Assert.isTrue) to check host, username, password and port only when the provider
requires Mailtrap, avoiding startup failure when provider=ses.

---

Nitpick comments:
In `@server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java`:
- Around line 35-41: Add validation on the Email.provider field to fail-fast on
typos: annotate the provider field in the nested AppProperties.Email class with
a constraint such as `@Pattern`(regexp = "^(ses|mailtrap)$", message = "Invalid
email provider, must be 'ses' or 'mailtrap'") (or an equivalent annotation) so
Spring’s configuration binding validates that provider is one of the supported
values and produces a clear error instead of a NoSuchBeanDefinitionException for
EmailProvider.
- Around line 34-35: Remove the ineffective `@Validated` annotations from the
nested static configuration classes (e.g., the Email class and the other nested
static classes referenced around lines 44-45 and 60-62) because `@Validated` only
works on Spring-managed beans; instead ensure validation is triggered via `@Valid`
on the parent property that binds the ConfigurationProperties. Locate the nested
static classes (such as Email) in AppProperties and delete their `@Validated`
annotations, and confirm the parent field that holds these nested types is
annotated with `@Valid` so validation still cascades.

In
`@server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/MailtrapConfig.java`:
- Line 35: In MailtrapConfig.java the javaMailProperties currently hardcodes
javaMailProperties.put("mail.debug", "false"); — make this value configurable by
reading a property (e.g., from Environment or `@Value`) or by checking the active
Spring profile in the MailtrapConfig class; replace the hardcoded "false" with
the fetched property (for example a key like spring.mail.properties.mail.debug
or a custom mail.debug property) so devs can enable debug in dev without code
changes and keep it off in prod.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java`:
- Around line 44-45: The AppProperties.email sender field 'from' currently only
has `@NotBlank` and lacks email format validation; update the AppProperties class
to add the `@Email` annotation on the 'from' field (alongside the existing
`@NotBlank`) so startup validation enforces a valid email format (include an
appropriate message if desired) and import javax.validation.constraints.Email;
ensure the change targets the 'from' field in AppProperties to match the
validation used in VerifyEmailDto/ResetPasswordDto.

---

Duplicate comments:
In `@server/src/main/java/org/eni/koinoniadaily/config/AppProperties.java`:
- Around line 35-36: Remove the `@Valid` annotation from the Mailtrap mailtrap
field in AppProperties to avoid unconditional bean validation, and instead add
conditional runtime checks in MailtrapConfig: implement a `@PostConstruct` method
(e.g., validate()) that checks props.getEmail().getProvider() equals "mailtrap"
and then asserts Mailtrap properties (getHost/getUsername/getPassword are
non-empty and getPort() > 0) using Spring Assert or similar to fail fast only
when Mailtrap is the selected provider.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #115

coderabbitai bot added a commit that referenced this pull request Feb 19, 2026
Docstrings generation was requested by @Cysteine12.

* #114 (comment)

The following files were modified:

* `server/src/main/java/org/eni/koinoniadaily/exceptions/EmailSendingException.java`
* `server/src/main/java/org/eni/koinoniadaily/exceptions/GlobalExceptionHandler.java`
* `server/src/main/java/org/eni/koinoniadaily/infrastructure/email/EmailService.java`
* `server/src/main/java/org/eni/koinoniadaily/infrastructure/email/config/MailtrapConfig.java`
* `server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/EmailProvider.java`
* `server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/MailtrapEmailProvider.java`
* `server/src/main/java/org/eni/koinoniadaily/infrastructure/email/providers/SesEmailProvider.java`
@Cysteine12 Cysteine12 merged commit 3818f93 into develop Feb 19, 2026
7 checks passed
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 19, 2026

No files have been changed in this PR. Unable to generate unit tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies enhancement New feature or request server Changes involving server application

Projects

None yet

Development

Successfully merging this pull request may close these issues.

S: Integrate Mailtrap Email Provider via SMTP

1 participant