A comprehensive REST API developed with Spring Boot to manage users and send email notifications using Mailpit as the SMTP server. It integrates seamlessly with PostgreSQL for data storage, and includes features for audit logging, Prometheus monitoring, Grafana dashboards, and automatic API documentation with Swagger/OpenAPI.
1. Features
- User Management: Complete CRUD operations for user management
- Email Notifications: Automated email sending for user events
- Audit Logging: Comprehensive tracking of all system actions
- Monitoring: Real-time metrics and health checks
- API Documentation: Interactive Swagger UI for API exploration
- Containerization: Easy deployment with Docker
- Database Integration: Robust PostgreSQL integration
- Metrics Visualization: Grafana dashboards for system monitoring
2. Requirements
- Java 17 or higher
- Docker and Docker Compose
- Maven for building the project
- PostgreSQL (if running without Docker)
- Mailpit (if running without Docker)
3. Technologies and Dependencies
- Spring Boot: Core framework for building Java applications
- Spring Boot Starter Web: For creating RESTful web applications
- Spring Boot Starter Mail: For handling emails
- Spring Boot Starter Data JPA: For database operations
- Spring Boot Starter Actuator: For monitoring and metrics
- PostgreSQL: Database for data persistence
- Mailpit: SMTP server for local email testing
- Docker & Docker Compose: For containerization and orchestration
- Prometheus: For metrics collection
- Grafana: For metrics visualization
- Swagger/OpenAPI: For API documentation
- Lombok: For reducing boilerplate code
- JUnit: For unit testing
4. Configuration and Execution
git clone https://github.com/andresWeitzel/email-api-service-MailPit
cd email-api-service-MailPit
- Before building and running the containers, make sure you have Docker running (for Windows, use Docker Desktop)
- Once installed, make sure Docker is running
docker --version
Important: Check that no other service (ej:postgres) is running as a daemon on the system, otherwise a connection problem will occur on the port.
- Once Docker is running, you can build and deploy the containers with docker compose (This command is only needed once to build).
- The container for Mailpit and Postgres will be created.
docker-compose up --build
- After creating the containers with Docker Compose, each time we are going to start the containers we will use the following command, otherwise we will run it from Docker Desktop. Start the environment in development mode. Every time you want to run the app in development, you won't need to compile the jar. Simply run the following command:
docker-compose up
- Another option is to launch the containers from Docker Desktop.
- Run the application
mvn spring-boot:run
5. Project Structure
email-api-service-MailPit/
├── src/
│ ├── main/
│ │ ├── java/com/microservice/
│ │ │ ├── config/ # Configuration classes
│ │ │ ├── controller/ # REST controllers
│ │ │ ├── dto/ # Data Transfer Objects
│ │ │ ├── exception/ # Exception handlers
│ │ │ ├── model/ # Entity models
│ │ │ ├── repository/ # Data access layer
│ │ │ ├── service/ # Business logic
│ │ │ └── EmailApiMailpitApplication.java
│ │ └── resources/
│ │ ├── application.yml # Application configuration
│ │ └── static/ # Static resources
│ └── test/ # Test classes
├── docker-compose.yml # Docker orchestration
├── Dockerfile # Application container
├── pom.xml # Maven dependencies
└── README.md # Project documentation
- Controllers: Handle HTTP requests and responses
- Services: Implement business logic
- Repositories: Data access layer
- DTOs: Data transfer objects for API communication
- Models: JPA entities for database mapping
- Config: Application configuration classes
- Exceptions: Custom exception handling
6. Processing Flow
-
User Management:
- Create, read, update, and delete user operations
- Email notifications sent automatically for user events
- Audit logging for all user-related actions
-
Email Processing:
- Email service integration with Mailpit SMTP server
- Template-based email generation
- Email delivery status tracking
-
Audit Logging:
- Comprehensive tracking of all system actions
- Filtering capabilities by entity, action, username, and details
- Historical data retention
-
Monitoring & Observability:
- Real-time health checks via Spring Boot Actuator
- Metrics collection with Prometheus
- Dashboard visualization with Grafana
7. API Examples
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john.doe@example.com"
}'Required Fields:
name: String (mandatory) - The name of the useremail: String (mandatory) - Valid email format
Response Examples:
Success Response (200):
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com"
}Error Responses:
Validation Error (400):
{
"errors": {
"name": "The name is mandatory"
},
"timestamp": "2025-07-14T17:21:59.3410006",
"status": 400
}Invalid Email Format (400):
{
"errors": {
"email": "The email is invalid"
},
"timestamp": "2025-07-14T17:21:59.3410006",
"status": 400
}Duplicate Email Error (400):
{
"errors": "Email is already in use: The email john.doe@exampletest.com already exists.",
"timestamp": "2025-07-14T17:30:37.1875171",
"status": 400
}📧 Mailpit Email (after successful creation):
From: noreply@email-api-service.com
To: john.doe@example.com
Subject: Account register Notification
Hello John Doe,
Thank you for registering with us!
curl -X GET http://localhost:8080/api/v1/usersResponse Examples:
Success Response (200):
{
"content": [
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com"
},
{
"id": 2,
"name": "Jane Smith",
"email": "jane.smith@example.com"
}
],
"pageable": {
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"offset": 0,
"pageNumber": 0,
"pageSize": 30,
"paged": true,
"unpaged": false
},
"totalElements": 2,
"totalPages": 1,
"last": true,
"size": 30,
"number": 0,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"numberOfElements": 2,
"first": true,
"empty": false
}curl -X PUT http://localhost:8080/api/v1/users/1 \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe Updated",
"email": "john.updated@example.com"
}'Response Examples:
Success Response (200):
{
"id": 1,
"name": "John Doe Updated",
"email": "john.updated@example.com"
}Error Responses:
User Not Found (404):
{
"errors": "User not found with id: 999",
"timestamp": "2025-07-14T17:45:12.9876543",
"status": 404
}Validation Error (400):
{
"errors": {
"email": "The email is invalid"
},
"timestamp": "2025-07-14T17:45:12.9876543",
"status": 400
}📧 Mailpit Email (after successful update):
From: noreply@email-api-service.com
To: john.updated@example.com
Subject: Account Update Notification
Hello John Doe Updated,
Your account has been successfully updated.
curl -X DELETE http://localhost:8080/api/v1/users/1Response Examples:
Success Response (200):
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com"
}Error Response:
User Not Found (404):
{
"errors": "User not found with id: 999",
"timestamp": "2025-07-14T17:50:25.1234567",
"status": 404
}📧 Mailpit Email (after successful deletion):
From: noreply@email-api-service.com
To: john.doe@example.com
Subject: Account Deletion Notification
Hello John Doe,
Your account has been successfully deleted.
curl -X GET http://localhost:8080/api/v1/users/1Response Examples:
Success Response (200):
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"createdAt": "2025-07-14T17:30:37.1875171",
"updatedAt": "2025-07-14T17:30:37.1875171"
}Error Response:
User Not Found (404):
{
"errors": "User not found with id: 999",
"timestamp": "2025-07-14T17:50:25.1234567",
"status": 404
}curl -X POST http://localhost:8080/api/v1/audit-log \
-H "Content-Type: application/json" \
-d '{
"entity": "User",
"action": "CREATE",
"username": "admin_user",
"details": "Created new user account with email john.doe@example.com"
}'Audit Log Fields:
entity: String - The entity being audited (e.g., "User")action: String - The action performed (e.g., "CREATE", "UPDATE", "DELETE")username: String - The username of the person performing the actiondetails: String - Detailed description of the actiontimestamp: LocalDateTime (optional) - When the action occurred
Response Examples:
Success Response (200):
{
"message": "Audit log created successfully"
}curl -X PUT http://localhost:8080/api/v1/audit-log/1 \
-H "Content-Type: application/json" \
-d '{
"entity": "User",
"action": "UPDATE",
"username": "admin_user",
"details": "Updated user account information"
}'Response Examples:
Success Response (200):
{
"id": 1,
"entity": "User",
"action": "UPDATE",
"username": "admin_user",
"details": "Updated user account information",
"timestamp": "2025-07-14T17:55:42.6543210"
}Error Response:
Audit Log Not Found (404):
{
"errors": "Audit log not found with id: 999",
"timestamp": "2025-07-14T17:55:42.6543210",
"status": 404
}# Filter by entity
curl -X GET "http://localhost:8080/api/v1/audit-log/entity?entity=User"
# Filter by action
curl -X GET "http://localhost:8080/api/v1/audit-log/action?action=CREATE"
# Filter by username
curl -X GET "http://localhost:8080/api/v1/audit-log/username?username=admin_user"
# Filter by details
curl -X GET "http://localhost:8080/api/v1/audit-log/details?details=Created+new+user"Response Examples:
Success Response (200) - Filtered Results:
{
"content": [
{
"id": 1,
"entity": "User",
"action": "CREATE",
"username": "admin_user",
"details": "Created new user account with email john.doe@example.com",
"timestamp": "2025-07-14T17:30:37.1875171"
},
{
"id": 3,
"entity": "User",
"action": "CREATE",
"username": "admin_user",
"details": "Created new user account with email jane.smith@example.com",
"timestamp": "2025-07-14T17:35:22.1234567"
}
],
"pageable": {
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"offset": 0,
"pageNumber": 0,
"pageSize": 30,
"paged": true,
"unpaged": false
},
"totalElements": 2,
"totalPages": 1,
"last": true,
"size": 30,
"number": 0,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"numberOfElements": 2,
"first": true,
"empty": false
}Empty Results Response (200):
{
"content": [],
"pageable": {
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"offset": 0,
"pageNumber": 0,
"pageSize": 30,
"paged": true,
"unpaged": false
},
"totalElements": 0,
"totalPages": 0,
"last": true,
"size": 30,
"number": 0,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"numberOfElements": 0,
"first": true,
"empty": true
}Common Response Status Codes:
- 200 OK: Request successful
- 201 Created: Resource created successfully
- 400 Bad Request: Validation error or invalid data
- 404 Not Found: Resource not found
- 409 Conflict: Resource conflict (e.g., duplicate email)
- 500 Internal Server Error: Server error
1. Start the Application:
docker-compose up2. Create a User:
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john.doe@example.com"
}'3. Check Mailpit for Email:
- Open http://localhost:8025 in your browser
- You should see a welcome email sent to john.doe@example.com
4. Get All Users:
curl -X GET http://localhost:8080/api/v1/users5. Update the User:
curl -X PUT http://localhost:8080/api/v1/users/1 \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe Updated",
"email": "john.updated@example.com"
}'6. Check Mailpit Again:
- Refresh http://localhost:8025
- You should see an update notification email
7. Delete the User:
curl -X DELETE http://localhost:8080/api/v1/users/18. Final Mailpit Check:
- Check http://localhost:8025 one more time
- You should see a deletion confirmation email
Try these to test error handling:
1. Create User with Missing Name:
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"email": "john.doe@example.com"
}'Expected Response:
{
"errors": {
"name": "The name is mandatory"
},
"timestamp": "2025-07-14T17:21:59.3410006",
"status": 400
}2. Create User with Invalid Email:
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "invalid-email"
}'Expected Response:
{
"errors": {
"email": "The email is invalid"
},
"timestamp": "2025-07-14T17:21:59.3410006",
"status": 400
}3. Create User with Duplicate Email:
# First, create a user
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john.doe@example.com"
}'
# Then try to create another user with the same email
curl -X POST http://localhost:8080/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Smith",
"email": "john.doe@example.com"
}'Expected Response:
{
"errors": "Email is already in use: The email john.doe@example.com already exists.",
"timestamp": "2025-07-14T17:30:37.1875171",
"status": 400
}📧 Mailpit Email (NO email sent for duplicate email error):
No email will be sent to Mailpit when there's a duplicate email error.
The user creation fails before the email service is called.
4. Get Non-existent User:
curl -X GET http://localhost:8080/api/v1/users/999Expected Response:
{
"errors": "User not found with id: 999",
"timestamp": "2025-07-14T17:50:25.1234567",
"status": 404
}📧 Mailpit Email (NO email sent for not found error):
No email will be sent to Mailpit when there's a "not found" error.
The operation fails before the email service is called.
Emails are sent to Mailpit ONLY for successful operations:
✅ CREATE User → Welcome email sent
✅ UPDATE User → Update notification email sent
✅ DELETE User → Deletion confirmation email sent
❌ Validation Errors → No email sent
❌ Duplicate Email → No email sent
❌ User Not Found → No email sent
-
Audit Log API
-
POST /api/v1/audit-log
➡️ http://localhost:8080/api/v1/audit-log -
PUT /api/v1/audit-log/{id}
➡️ http://localhost:8080/api/v1/audit-log/{id} -
DELETE /api/v1/audit-log/{id}
➡️ http://localhost:8080/api/v1/audit-log/{id} -
GET /api/v1/audit-log
➡️ http://localhost:8080/api/v1/audit-log -
GET /api/v1/audit-log/entity?entity={entityName}
➡️ http://localhost:8080/api/v1/audit-log/entity?entity=User -
GET /api/v1/audit-log/action?action={actionType}
➡️ http://localhost:8080/api/v1/audit-log/action?action=CREATE -
GET /api/v1/audit-log/username?username={username}
➡️ http://localhost:8080/api/v1/audit-log/username?username=admin -
GET /api/v1/audit-log/details?details={details}
➡️ http://localhost:8080/api/v1/audit-log/details?details=Created+new+user
-
-
User API
-
POST /api/v1/users
➡️ http://localhost:8080/api/v1/users -
PUT /api/v1/users/{id}
➡️ http://localhost:8080/api/v1/users/{id} -
DELETE /api/v1/users/{id}
➡️ http://localhost:8080/api/v1/users/{id} -
GET /api/v1/users/{id}
➡️ http://localhost:8080/api/v1/users/{id} -
GET /api/v1/users
➡️ http://localhost:8080/api/v1/users
-
-
Swagger UI:
-
GET /swagger-ui/index.html
➡️ http://localhost:8080/swagger-ui/index.html -
GET /v3/api-docs– Documentación OpenAPI
➡️ http://localhost:8080/v3/api-docs
-
-
Actuator Endpoints:
-
GET /actuator
➡️ http://localhost:8080/actuator -
GET /actuator/health
➡️ http://localhost:8080/actuator/health -
GET /actuator/metrics
➡️ http://localhost:8080/actuator/metrics -
GET /actuator/prometheus
➡️ http://localhost:8080/actuator/prometheus -
GET /actuator/env
➡️ http://localhost:8080/actuator/env
-
-
MailPit:
-
Web UI
➡️ http://localhost:8025 -
SMTP Server➡️smtp://localhost:1025
-
-
Prometheus:
UI Web➡️ http://localhost:9090
-
Grafana:
UI Web➡️ http://localhost:3000
🧾 Credenciales por defecto:- Usuario:
admin - Contraseña:
admin
- Usuario:
-
PostgreSQL:
JDBC URL
➡️jdbc:postgresql://localhost:5432/mydatabase- Usuario:
user - Contraseña:
password
- Usuario:
When you access Mailpit at http://localhost:8025, you'll see emails like these:
From: noreply@email-api-service.com
To: john.doe@example.com
Subject: Welcome to Our Service!
Dear John Doe,
Welcome to our service! Your account has been successfully created.
Account Details:
- Name: John Doe
- Email: john.doe@example.com
- Account ID: 1
Thank you for joining us!
Best regards,
The Email API Service Team
From: noreply@email-api-service.com
To: john.updated@example.com
Subject: Your Account Has Been Updated
Dear John Doe Updated,
Your account information has been successfully updated.
Updated Details:
- Name: John Doe Updated
- Email: john.updated@example.com
- Account ID: 1
If you didn't request this change, please contact support immediately.
Best regards,
The Email API Service Team
From: noreply@email-api-service.com
To: john.doe@example.com
Subject: Account Deletion Confirmation
Dear John Doe,
Your account has been successfully deleted from our system.
Account Details:
- Name: John Doe
- Email: john.doe@example.com
- Account ID: 1
All your data has been permanently removed.
Best regards,
The Email API Service Team
Mailpit Features:
- Email Preview: View HTML and text versions of emails
- Email Details: See headers, attachments, and metadata
- Search: Filter emails by sender, recipient, or content
- Export: Download emails for testing purposes
- Real-time: Emails appear instantly when sent by the API
8. Implemented Validations
-
User Data Validation:
- Email format validation
- Username uniqueness check
- Required field validation
- Data integrity constraints
-
Email Validation:
- SMTP server connectivity
- Email format verification
- Delivery status tracking
-
Database Validation:
- Connection health checks
- Transaction rollback on errors
- Data consistency validation
-
API Validation:
- Request payload validation
- HTTP status code handling
- Error response formatting
9. Monitoring & Reports
The system provides comprehensive monitoring and reporting capabilities:
- Health Checks: Application health monitoring via Spring Boot Actuator
- Metrics Collection: Prometheus metrics for performance monitoring
- Dashboard Visualization: Grafana dashboards for system monitoring
- Audit Reports: Comprehensive audit trail for compliance
- Email Delivery Reports: Email sending status and delivery tracking
10. Contributing
- Fork the project
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
11. License
This project is under the MIT License - see the LICENSE file for details.
