An email attachment is a file (report, PDF, image, document) sent along with the email message. In Spring Boot you create a multipart MimeMessage with MimeMessageHelper and add files using addAttachment(). The file can come from disk, from a database, or be generated in memory as a ByteArrayResource. It is used for reports, invoices, certificates, offer letters, and receipts.
Features
- Attach one or many files to a single email
- Generate files in memory, so nothing is written to disk
- Set the file name and content type (
text/csv,application/pdf,image/png) - Works with the same
spring.mail.*SMTP configuration as 12.1 and 12.2 - Combines with HTML bodies, since the multipart message supports both
- Files can be attached from disk (
FileSystemResource), memory (ByteArrayResource), or the classpath (ClassPathResource)
Email Attachment Types
| Type | Resource class | When to use |
|---|---|---|
| In-memory attachment | ByteArrayResource |
Reports generated on the fly; used in this example |
| File-system attachment | FileSystemResource |
Files already stored on the server (uploaded certificates, saved PDFs) |
| Classpath attachment | ClassPathResource |
Fixed files bundled with the app (terms and conditions, brochures) |
| Inline attachment | helper.addInline(cid, resource) |
Images shown inside the HTML body, such as a college logo |
| Multiple attachments | Call addAttachment() repeatedly |
Sending a report and a receipt together |
Hands-on Experiment: Creating a spring boot application to understand how files can be attached to outgoing emails.
The following steps are involved in developing this hands-on experiment.
Step 1: Generate the Project
Step 2: Project Structure
Step 3: pom.xml
Step 4: application.properties
Step 5: Create Entity Class
Step 6: Create Repository Interface
Step 7: Create Service Class
Step 8: Create Controller Class
Step 9: Main Application Class
Step 10: Run the Main Application Class
Step 1: Configure the Project on Spring Initializr
Go to start.spring.io and set:
- Project: Maven
- Language: Java
- Spring Boot version: 3.2.x
- Group: com.example
- Artifact: attachment
- Name: attachment
- Package name: com.example.attachment
- Packaging: Jar
- Java: 17
- Dependencies: Spring Web, Spring Data JPA, H2 Driver.
Click Generate to download the ZIP, then extract and import it into your IDE as a Maven project.
Step 2: Generated Project Structure

Step 3: Explore pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>student-attachment-demo</artifactId>
<version>1.0.0</version>
<name>student-attachment-demo</name>
<description>Email Attachments - Student report sent as attachment</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Step 4: application.properties
spring.application.name=student-attachment-demo
# Create the database first: CREATE DATABASE student_smtp_db;
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
server.port=8082
# ---------- SMTP (Gmail example) ----------
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=ravi@gmail.com
# Use a 16-character Gmail App Password (NOT your normal password)
spring.mail.password=
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000
# ---------- Custom ----------
app.mail.from=your-email@gmail.com
# Attachment size limit is decided by the mail provider (Gmail: 25 MB)
Step 5: Create Entity Class
package com.example.attachment.entity;
import jakarta.persistence.*;
@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false, unique = true)
private String email;
private String course;
private String department;
private Integer marks;
public Student() {
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getCourse() { return course; }
public void setCourse(String course) { this.course = course; }
public String getDepartment() { return department; }
public void setDepartment(String department) { this.department = department; }
public Integer getMarks() { return marks; }
public void setMarks(Integer marks) { this.marks = marks; }
}
Step 6: Create below Repository Interface
package com.example.attachment.repository;
import com.example.attachment.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
boolean existsByEmail(String email);
}
Step 7: Create below Service class
package com.example.attachment.service;
import com.example.attachment.entity.Student;
import com.example.attachment.repository.StudentRepository;
import jakarta.mail.internet.MimeMessage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.List;
@Service
public class StudentService {
private final StudentRepository studentRepository;
private final JavaMailSender mailSender;
@Value("${app.mail.from}")
private String fromAddress;
public StudentService(StudentRepository studentRepository, JavaMailSender mailSender) {
this.studentRepository = studentRepository;
this.mailSender = mailSender;
}
public Student add(Student student) {
if (studentRepository.existsByEmail(student.getEmail())) {
throw new IllegalArgumentException("Email already registered: " + student.getEmail());
}
return studentRepository.save(student);
}
public List<Student> getAll() {
return studentRepository.findAll();
}
// 1. Generate the report in memory (CSV) - no file is saved on disk
public byte[] generateReport() {
StringBuilder csv = new StringBuilder();
csv.append("ID,Name,Email,Course,Department,Marks\n");
for (Student s : studentRepository.findAll()) {
csv.append(s.getId()).append(',')
.append(clean(s.getName())).append(',')
.append(clean(s.getEmail())).append(',')
.append(clean(s.getCourse())).append(',')
.append(clean(s.getDepartment())).append(',')
.append(s.getMarks() == null ? "" : s.getMarks())
.append('\n');
}
return csv.toString().getBytes(StandardCharsets.UTF_8);
}
// 2. Attach the report to the email and send it
public int sendReport(String toEmail) throws Exception {
byte[] report = generateReport();
int count = (int) studentRepository.count();
MimeMessage mimeMessage = mailSender.createMimeMessage();
// true = multipart mode, required for attachments
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
helper.setFrom(fromAddress);
helper.setTo(toEmail);
helper.setSubject("Student Report - " + LocalDate.now());
helper.setText("Hello,\n\nPlease find the attached student report containing "
+ count + " student(s).\n\nRegards,\nAdmissions Office");
helper.addAttachment("student-report-" + LocalDate.now() + ".csv",
new ByteArrayResource(report), "text/csv");
mailSender.send(mimeMessage);
return count;
}
// Avoid commas breaking the CSV columns
private String clean(String value) {
return value == null ? "" : value.replace(",", " ");
}
}
Step 8: Create Controller class
package com.example.attachment.controller;
import com.example.attachment.entity.Student;
import com.example.attachment.service.StudentService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/students")
public class StudentController {
private final StudentService studentService;
public StudentController(StudentService studentService) {
this.studentService = studentService;
}
@PostMapping
public ResponseEntity<?> add(@RequestBody Student student) {
try {
return ResponseEntity.status(HttpStatus.CREATED).body(studentService.add(student));
} catch (IllegalArgumentException ex) {
return ResponseEntity.badRequest().body(Map.of("error", ex.getMessage()));
}
}
@GetMapping
public List<Student> getAll() {
return studentService.getAll();
}
// Download the same report in the browser (to preview what will be attached)
@GetMapping("/report/download")
public ResponseEntity<byte[]> download() {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=student-report.csv")
.contentType(MediaType.parseMediaType("text/csv"))
.body(studentService.generateReport());
}
// Generate the report and email it as an attachment
@PostMapping("/report/email")
public ResponseEntity<?> emailReport(@RequestBody Map<String, String> request) {
String to = request.get("to");
if (to == null || to.isBlank()) {
return ResponseEntity.badRequest().body(Map.of("error", "'to' email is required"));
}
try {
int count = studentService.sendReport(to);
return ResponseEntity.ok(Map.of("message", "Report emailed successfully",
"to", to, "students", count));
} catch (Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Map.of("error", "Mail failed: " + ex.getMessage()));
}
}
}
Step 9: Main Application
package com.example.attachment;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AttachmentApplication {
public static void main(String[] args) {
SpringApplication.run(AttachmentApplication.class, args);
}
}
Step 10: Run the AttachmentApplication


