Skip to content

Commit f3f9ade

Browse files
authored
Release v1.0.1
- Email 전송 API fix - CI/CD 캐싱 도입
2 parents 6990b3c + bd2934c commit f3f9ade

File tree

7 files changed

+170
-97
lines changed

7 files changed

+170
-97
lines changed

.github/workflows/ci.yml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,26 @@ jobs:
1818
java-version: '21'
1919
cache: gradle
2020

21+
- name: Cache Gradle packages
22+
uses: actions/cache@v3
23+
with:
24+
path: |
25+
~/.gradle/caches
26+
~/.gradle/wrapper
27+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
28+
restore-keys: |
29+
${{ runner.os }}-gradle-
30+
31+
- name: Cache Gradle Build
32+
uses: actions/cache@v3
33+
with:
34+
path: build
35+
key: ${{ runner.os }}-gradle-build-${{ github.sha }}
36+
restore-keys: |
37+
${{ runner.os }}-gradle-build-
38+
2139
- name: Grant execute permission for gradlew
2240
run: chmod +x gradlew
2341

2442
- name: Build with Gradle
25-
run: ./gradlew clean build
43+
run: ./gradlew clean build --build-cache

.github/workflows/cicd.yml

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,40 @@ jobs:
1111
- name: Checkout code
1212
uses: actions/[email protected]
1313

14+
- name: Set up JDK 21
15+
uses: actions/[email protected]
16+
with:
17+
distribution: 'temurin'
18+
java-version: '21'
19+
cache: gradle
20+
21+
- name: Cache Gradle packages
22+
uses: actions/cache@v3
23+
with:
24+
path: |
25+
~/.gradle/caches
26+
~/.gradle/wrapper
27+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
28+
restore-keys: |
29+
${{ runner.os }}-gradle-
30+
31+
- name: Set up Docker Buildx
32+
uses: docker/setup-buildx-action@v3
33+
1434
- name: Log in to Docker Hub
1535
uses: docker/[email protected]
1636
with:
1737
username: ${{ secrets.DOCKER_USERNAME }}
1838
password: ${{ secrets.DOCKER_PASSWORD }}
1939

40+
- name: Cache Docker layers
41+
uses: actions/cache@v3
42+
with:
43+
path: /tmp/.buildx-cache
44+
key: ${{ runner.os }}-buildx-${{ github.sha }}
45+
restore-keys: |
46+
${{ runner.os }}-buildx-
47+
2048
- name: Build and Push Docker image
2149
if: github.ref == 'refs/heads/main'
2250
uses: docker/[email protected]
@@ -26,11 +54,17 @@ jobs:
2654
push: true
2755
tags: ${{ secrets.DOCKER_USERNAME }}/${{ secrets.PROD_IMAGE_NAME }}:latest
2856
platforms: linux/amd64
57+
cache-from: type=local,src=/tmp/.buildx-cache
58+
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
59+
60+
- name: Move cache
61+
run: |
62+
rm -rf /tmp/.buildx-cache
63+
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
2964
3065
deploy:
3166
runs-on: ubuntu-latest
3267
needs: build
33-
3468
steps:
3569
- name: SSH to Server and Deploy
3670
if: github.ref == 'refs/heads/main'
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package dmu.dasom.api.domain.email.config;
2+
3+
import org.springframework.beans.factory.annotation.Value;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.mail.javamail.JavaMailSender;
7+
import org.springframework.mail.javamail.JavaMailSenderImpl;
8+
9+
import java.util.Properties;
10+
11+
@Configuration
12+
public class EmailConfig {
13+
14+
@Value("${spring.mail.username}")
15+
private String username;
16+
@Value("${spring.mail.password}")
17+
private String password;
18+
19+
@Bean
20+
public JavaMailSender javaMailSender() {
21+
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
22+
mailSender.setHost("smtp.gmail.com");
23+
mailSender.setPort(587);
24+
mailSender.setUsername(username);
25+
mailSender.setPassword(password);
26+
27+
Properties props = mailSender.getJavaMailProperties();
28+
props.put("mail.transport.protocol", "smtp");
29+
props.put("mail.smtp.auth", "true");
30+
props.put("mail.smtp.starttls.enable", "true");
31+
props.put("mail.debug", "true");
32+
33+
return mailSender;
34+
}
35+
}

src/main/java/dmu/dasom/api/domain/email/service/EmailService.java

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,36 @@
1717
@Service
1818
public class EmailService {
1919

20-
private JavaMailSender javaMailSender;
21-
private TemplateEngine templateEngine;
20+
private final TemplateEngine templateEngine;
21+
private final JavaMailSender javaMailSender;
22+
2223
@Value("${spring.mail.username}")
2324
private String from;
2425

2526
public void sendEmail(String to, String name, MailType mailType) throws MessagingException {
2627
if (mailType == null){
2728
throw new CustomException(ErrorCode.MAIL_TYPE_NOT_VALID);
2829
}
30+
2931
// 메일 제목 및 템플릿 설정
3032
String subject;
3133
String emailContent;
32-
String buttonUrl = "#";
34+
String buttonUrl = "https://dmu-dasom.or.kr/recruit/result";
3335
String buttonText;
36+
3437
switch (mailType) {
3538
case DOCUMENT_RESULT -> {
3639
subject = "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 서류 결과 안내";
37-
emailContent = "먼저 다솜 34기에 많은 관심을 갖고 지원해 주셔서 감사드리며,<br>" +
38-
"내부 서류 평가 결과 및 추후 일정에 관해 안내드리고자 이메일을 발송하게 되었습니다.<br>" +
39-
"모집 폼 합/불합 결과는 아래 버튼 혹은 홈페이지를 통해 확인이 가능합니다.";
40+
emailContent = "먼저 다솜 34기에 많은 관심을 두고 지원해 주셔서 감사드리며,<br>" +
41+
"내부 서류 평가 결과 및 추후 일정에 관해 안내해드리고자 이메일을 발송하게 되었습니다.<br>" +
42+
"서류 전형 결과는 아래 버튼 혹은 홈페이지를 통해 확인이 가능합니다.";
4043
buttonText = "서류 결과 확인하기";
4144
}
4245
case FINAL_RESULT -> {
43-
subject = "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 최종 합격 안내";
44-
emailContent = "먼저 다솜 34기에 많은 관심을 갖고 지원해 주셔서 감사드리며,<br>" +
45-
"최종 면접 결과 및 추후 일정에 관해 안내드리고자 이메일을 발송하게 되었습니다.<br>" +
46-
"모집 폼 합/불합 결과는 아래 버튼 혹은 홈페이지를 통해 확인이 가능합니다.";
46+
subject = "동양미래대학교 컴퓨터소프트웨어공학과 전공 동아리 DASOM 최종 면접 결과 안내";
47+
emailContent = "먼저 다솜 34기에 많은 관심을 두고 지원해 주셔서 감사드리며,<br>" +
48+
"최종 면접 결과 및 추후 일정에 관해 안내해드리고자 이메일을 발송하게 되었습니다.<br>" +
49+
"최종 면접 결과는 아래 버튼 혹은 홈페이지를 통해 확인이 가능합니다.";
4750
buttonText = "최종 결과 확인하기";
4851
}
4952
default -> throw new IllegalStateException("Unexpected value: " + mailType);
@@ -66,7 +69,10 @@ public void sendEmail(String to, String name, MailType mailType) throws Messagin
6669
helper.setTo(to);
6770
helper.setSubject(subject);
6871
helper.setText(htmlBody, true);
69-
helper.setFrom(from);
72+
helper.setFrom((from != null && !from.isEmpty()) ? from : "[email protected]");
73+
74+
// Content-Type을 명시적으로 설정
75+
message.setContent(htmlBody, "text/html; charset=utf-8");
7076

7177
javaMailSender.send(message);
7278
}

src/main/java/dmu/dasom/api/global/admin/controller/AdminController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public ResponseEntity<Void> modifyRecruitSchedule(@Valid @RequestBody final Recr
153153
public ResponseEntity<Void> sendEmailsToApplicants(
154154
@RequestParam
155155
@Parameter(description = "메일 발송 타입", examples = {
156-
@ExampleObject(name = "서류 합격 메일", value = "DOCUMENT_PASS"),
156+
@ExampleObject(name = "서류 합격 메일", value = "DOCUMENT_RESULT"),
157157
@ExampleObject(name = "최종 결과 메일", value = "FINAL_RESULT")
158158
}) MailType mailType
159159
) {

src/main/resources/template/email-template.html renamed to src/main/resources/templates/email-template.html

Lines changed: 63 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -3,139 +3,119 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<meta name="color-scheme" content="light dark">
7+
<meta name="supported-color-schemes" content="light dark">
68
<title>이메일 안내</title>
7-
<link rel="stylesheet" as="style" crossorigin href="https://cdn.jsdelivr.net/gh/orioncactus/[email protected]/dist/web/static/pretendard.css" />
8-
<style>
9-
body {
9+
</head>
10+
<body style="
1011
background-color: #17171B;
11-
color: white;
12+
color: white !important;
1213
font-family: 'Pretendard', sans-serif;
1314
display: flex;
1415
justify-content: center;
1516
align-items: center;
1617
height: 100vh;
17-
margin: 0;
18-
}
19-
20-
.email-container {
18+
margin: 0;">
19+
<div style="
2120
width: 740px;
2221
height: 680px;
2322
background: #17171B;
2423
padding: 30px;
25-
position: relative;
26-
}
27-
28-
.logo {
24+
position: relative;">
25+
<div style="
2926
display: flex;
3027
justify-content: center;
3128
position: relative;
32-
margin-bottom: 20px;
33-
}
34-
35-
.logo img {
36-
width: 21px;
37-
height: 24px;
38-
border-radius: 3px;
39-
}
40-
41-
.divider {
29+
margin-bottom: 20px;">
30+
<div style="
4231
width: 100%;
4332
display: flex;
4433
justify-content: space-between;
45-
align-items: center;
46-
}
47-
48-
.divider .line {
34+
align-items: center;">
35+
<div style="
36+
flex: 1;
37+
border-top: 1px solid #00B493;
38+
margin: 0 10px;">
39+
40+
</div>
41+
<img src="https://dmu-dasom.or.kr/static/media/dasomLogo.c82d220d8093c3cb8d7fc0b148cafcd1.svg" alt="로고" style="
42+
width: 21px;
43+
height: 24px;
44+
border-radius: 3px;">
45+
<div style="
4946
flex: 1;
5047
border-top: 1px solid #00B493;
51-
margin: 0 10px;
52-
}
48+
margin: 0 10px;">
49+
</div>
50+
</div>
51+
</div>
5352

54-
.title {
53+
<div style="
5554
font-size: 48px;
5655
font-weight: 900;
5756
color: #00B493;
58-
margin-bottom: 30px;
59-
}
60-
61-
.greeting {
57+
margin-bottom: 30px;">
58+
DASOM
59+
</div>
60+
<div style="
6261
font-size: 20px;
6362
font-weight: 600;
64-
margin-bottom: 40px;
65-
}
63+
margin-bottom: 5px;
64+
color: white !important;"
65+
th:text="${name} + '님 안녕하세요.'">
66+
</div>
67+
<div style="
68+
font-size: 20px;
69+
font-weight: 600;
70+
margin-bottom: 5px;
71+
color: white !important;">
72+
컴퓨터공학부 전공동아리 다솜입니다.
73+
</div>
6674

67-
.content {
75+
<div style="
6876
font-size: 16px;
6977
font-weight: 400;
7078
line-height: 2.5;
7179
text-align: right;
7280
margin-bottom: 40px;
73-
}
74-
75-
.contact {
76-
font-size: 16px;
77-
font-weight: 400;
78-
line-height: 1.5;
79-
}
81+
color: white !important;"
82+
th:utext="${emailContent}">
83+
</div>
8084

81-
.button-container {
82-
display: flex;
85+
<div style="display: flex;
8386
justify-content: flex-end;
84-
margin-bottom: 40px;
85-
}
86-
87-
.button {
87+
margin-bottom: 40px;">
88+
<a th:href="${buttonUrl}"
89+
style="
8890
background: #00B493;
89-
color: white;
91+
color: white !important;
9092
font-size: 16px;
9193
font-weight: 400;
9294
padding: 10px 20px;
9395
border-radius: 5px;
9496
display: flex;
9597
align-items: center;
96-
text-decoration: none;
97-
}
98-
99-
.button:hover {
100-
background: #00987A;
101-
}
102-
103-
.button .arrow {
98+
text-decoration: none;">
99+
<span th:text="${buttonText}">
100+
</span>
101+
<span style="
104102
border: solid white;
105103
border-width: 0 2px 2px 0;
106104
display: inline-block;
107105
padding: 5px;
108106
transform: rotate(-45deg);
109-
margin-left: 10px;
110-
}
111-
</style>
112-
</head>
113-
<body>
114-
<div class="email-container">
115-
<div class="logo">
116-
<div class="divider">
117-
<div class="line"></div>
118-
<img src="logo.png" alt="로고">
119-
<div class="line"></div>
120-
</div>
121-
</div>
122-
123-
<div class="title">DASOM</div>
124-
<div class="greeting" th:text="${name} + '님 안녕하세요.'"></div>
125-
<div>컴퓨터공학부 전공동아리 다솜입니다.</div>
126-
127-
<div class="content" th:utext="${emailContent}"></div>
128-
129-
<div class="button-container">
130-
<a th:href="${buttonUrl}" class="button">
131-
<span th:text="${buttonText}"></span> <span class="arrow"></span>
107+
margin-left: 10px;">
108+
</span>
132109
</a>
133110
</div>
134111

135-
<div class="contact">
112+
<div style="font-size: 16px;
113+
font-weight: 400;
114+
line-height: 1.5;
115+
color: white !important;">
136116
또한, 문의 사항은 본 메일에 회신 또는 아래 번호로 편하게 연락 부탁드립니다.<br>
137117
010-6361-3481
138118
</div>
139119
</div>
140120
</body>
141-
</html>
121+
</html>
File renamed without changes.

0 commit comments

Comments
 (0)