diff --git a/README.md b/README.md index 14fe824..6d783a0 100644 --- a/README.md +++ b/README.md @@ -11,17 +11,15 @@ 2024.10.12 - 2024.11.06 ### ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ ๊ตฌ์„ฑ์› - - Team Leader: ๊น€ํ˜„์šฐ - - Member 2: ๋ฐ•๋ฏผ์ˆ˜ + - Team Leader 1: ๊น€ํ˜„์šฐ + - Team Leader 2: ๋ฐ•๋ฏผ์ˆ˜ - Member 3: ํ™์ง€๋ฏผ - Member 4: ์ด์„œํ˜„ - Member 5: ์‹ ์˜ˆ๋ฆฐ ### โš™๏ธ ๊ฐœ๋ฐœํ™˜๊ฒฝ - - Java Version: `JDK22` - - IDE: - - Framework: - - ORM: + - Java Version: `JDK 22` + - IDE: `Eclips 4.33.0` ## ๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ @@ -35,336 +33,1163 @@ src โ”œโ”€โ”€ FileHandler.java โ””โ”€โ”€ MimeMessageBuilder.java โ””โ”€โ”€ email.smtp - โ”œโ”€โ”€ Auth.java โ”œโ”€โ”€ Client.java - โ””โ”€โ”€ email.main - โ””โ”€โ”€ EmailApp.java + โ”œโ”€โ”€ EmailServiceWithNaver.java + โ””โ”€โ”€ EmailWithNaver.java + lib + โ””โ”€โ”€ flatlaf-3.5.2.jar ``` ## ๐Ÿ“Œ ์ฃผ์š” ๊ธฐ๋Šฅ 1. **๋กœ๊ทธ์ธ** - - ์‚ฌ์šฉ์ž๊ฐ€ `LoginGUI`์—์„œ ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค. - - ์ž…๋ ฅ๋œ ์ด๋ฉ”์ผ์€ `Auth` ๊ฐ์ฒด์— ์ „๋‹ฌ๋˜์–ด ์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ์ฃผ์†Œ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. - - ์ด๋ฉ”์ผ ์ฃผ์†Œ๊ฐ€ ์œ ํšจํ•˜๊ณ  ์—ฐ๊ฒฐ์ด ์„ฑ๊ณตํ•˜๋ฉด `SendEmailGUI`๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. + - ์‚ฌ์šฉ์ž๋Š” `LoginGUI`์—์„œ ์ œ๊ณตํ•˜๋Š” ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํ•„๋“œ์— ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•œ ํ›„, Login ๋ฒ„ํŠผ์„ ๋ˆ„๋ฆ…๋‹ˆ๋‹ค. + - ์ž…๋ ฅ๋œ ์ด๋ฉ”์ผ์€ ๊ฐ์ฒด์— ์ „๋‹ฌ๋˜๊ณ , `LoginGUI`๋Š” ์ž…๋ ฅ๋œ ์ด๋ฉ”์ผ์ด ์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ์ฃผ์†Œ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. + - ์ด๋ฉ”์ผ ์ฃผ์†Œ๊ฐ€ ์œ ํšจํ•˜๊ณ , ์—ฐ๊ฒฐ์— ์„ฑ๊ณตํ•˜๋ฉด `SendEmailGUI`๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. 2. **์ด๋ฉ”์ผ ์ „์†ก** - - `SendEmailGUI`์—์„œ ์‚ฌ์šฉ์ž๋Š” ์ด๋ฉ”์ผ ๋ฉ”์‹œ์ง€์™€ ์ฒจ๋ถ€ํ•  ํŒŒ์ผ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. - - ์‚ฌ์šฉ์ž๊ฐ€ ์ „์†ก ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด `Client` ํด๋ž˜์Šค๊ฐ€ ํ˜ธ์ถœ๋˜์–ด, ์ž…๋ ฅ๋œ ๋ฉ”์‹œ์ง€์™€ ํŒŒ์ผ์— ๋Œ€ํ•œ Base64 ์ธ์ฝ”๋”ฉ ๋“ฑ์˜ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. - - ์ฒ˜๋ฆฌ๋œ ๋‚ด์šฉ์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ๊ฒ€์ฆ ํ›„, ์ตœ์ข…์ ์œผ๋กœ ์ด๋ฉ”์ผ์ด ์ „์†ก๋ฉ๋‹ˆ๋‹ค. + - `SendEmailGUI`์—์„œ ์‚ฌ์šฉ์ž๋Š” ์ˆ˜์‹ ์ž, ์ œ๋ชฉ, ๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค. Attach File ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์ฒจ๋ถ€ํ•  ํŒŒ์ผ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + - ์‚ฌ์šฉ์ž๊ฐ€ Send ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด `Client` ํด๋ž˜์Šค๊ฐ€ ํ˜ธ์ถœ๋˜์–ด, ์ž…๋ ฅ๋œ ๋ฉ”์‹œ์ง€์™€ ํŒŒ์ผ์— ๋Œ€ํ•œ Base64 ์ธ์ฝ”๋”ฉ, MIMEํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ ์ฒ˜๋ฆฌ๊ฐ€ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. + - ์ˆ˜์‹ ์ž, ์ œ๋ชฉ, ๋ฉ”์‹œ์ง€๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ์ง€ ๊ฒ€์ฆํ•œ ํ›„, ์„ ํƒ๋œ ํŒŒ์ผ๊ณผ ํ•จ๊ป˜ ์ตœ์ข…์ ์œผ๋กœ ์ด๋ฉ”์ผ์ด ์ „์†ก๋ฉ๋‹ˆ๋‹ค. + - ํ•œ๋ฒˆ์— ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฉ”์ผ์„ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + - Quit ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, SMTP ์„œ๋ฒ„ ์—ฐ๊ฒฐ์„ ์ข…๋ฃŒํ•˜๊ณ  ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค. -4. **ํŒŒ์ผ ์ฒจ๋ถ€** - - ์‚ฌ์šฉ์ž๊ฐ€ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ๋Š” ํŒŒ์ผ์˜ ํ˜•์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. - - ์ด๋ฏธ์ง€ ํŒŒ์ผ (jpg, png ๋“ฑ) - - ๋ฌธ์„œ ํŒŒ์ผ (pdf, docx ๋“ฑ) - - ํ…์ŠคํŠธ ํŒŒ์ผ (txt ๋“ฑ) +3. **ํŒŒ์ผ ์ฒจ๋ถ€** + - `FileHandler`์—์„œ ํŒŒ์ผ์ด ์œ ํšจํ•œ์ง€, MIME ํƒ€์ž…์ด ์œ ํšจํ•œ์ง€ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค. (์œ ํšจํ•œ ํŒŒ์ผ ํ˜•์‹: ์ด๋ฏธ์ง€ ํŒŒ์ผ, PDF, ํ…์ŠคํŠธ ํŒŒ์ผ) + - ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜๋ฉด ํŒŒ์ผ์ด ์ฒจ๋ถ€๋˜์—ˆ๋‹ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. + - ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ํŒŒ์ผ์ด ์—†๋‹ค๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. + ## ๐Ÿ”Ž ํŒจํ‚ค์ง€ ์ƒ์„ธ ์„ค๋ช… -### 1. `email.gui` -
- LoginGUI.java +### 1. *email.gui* - ```javascript - - ``` -
- -
- SendEmailGUI.java - - ```javascript - - ``` -
- -- `LoginGUI.java`: ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์ธํ„ฐํŽ˜์ด์Šค -- `SendEmailGUI.java`: ์ด๋ฉ”์ผ ์ „์†ก ์ธํ„ฐํŽ˜์ด์Šค - -### 2. `email.mime` -
- FileHandler.java - - ```javascript - package email.mime; - - import java.nio.file.Files; - import java.nio.file.Path; - import java.nio.file.Paths; - import java.io.File; - import java.io.IOException; - import java.nio.file.StandardCopyOption; - - public class FileHandler { - - // ํŒŒ์ผ์„ ์ฒจ๋ถ€ํ•˜๋Š” ๋ฉ”์†Œ๋“œ - // filePath๋กœ ์ง€์ •๋œ ํŒŒ์ผ์„ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธ ํ›„ ์ฒ˜๋ฆฌ - public void attachFile(String filePath) { - File file = new File(filePath); - if (file.exists()) { - if (isValidFileType(file)) { - // ์œ ํšจํ•œ ํŒŒ์ผ์ด๋ฉด ์ฒจ๋ถ€ - } else { - System.out.println("์œ ํšจํ•˜์ง€๊ฐ€ ์•Š์ž–์•„."); // ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ - } - } else { - System.out.println("ํŒŒ์ผ์ด ์—†์ž–์•„."); // ํŒŒ์ผ์ด ์—†๋Š” ๊ฒฝ์šฐ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ - } - } - - // ํŒŒ์ผ์˜ MIME ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ - // ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ž…๋ ฅ๋ฐ›์•„ ํ•ด๋‹น ํŒŒ์ผ์˜ MIME ํƒ€์ž…์„ ๋ฐ˜ํ™˜ - // javax.activation์œผ๋กœ๋„ ๊ตฌํ˜„ํ•˜๋Š”๊ฒŒ ์žˆ๊ธดํ•œ๋ฐ ์ด๊ฒŒ ๊ธฐ๋ณธ jdk๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋น ์ ธ์žˆ์–ด์„œ ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ถ”๊ฐ€ํ•ด์•ผํ•จ. - // ์žฅ๋‹จ์  ๋น„๊ต mimeํŒŒํŠธ๋ž‘ ๋…ผ์˜ ํ•„์š”ํ• ๋“ฏ - public String getMimeType(String filePath) { - Path path = Paths.get(filePath); - try { - return Files.probeContentType(path); // MIME ํƒ€์ž… ํƒ์ง€ - } catch (IOException e) { - e.printStackTrace(); // ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์ถœ๋ ฅ - return "์ด์ƒํ•œ ํƒ€์ž…์ธ๋ฐ์š”"; // ์•Œ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ - } - } - - // ํŒŒ์ผ ํƒ€์ž… ์œ ํšจ์„ฑ ํ™•์ธ ๋ฉ”์†Œ๋“œ - // ์ด๋ฏธ์ง€, PDF, ํ…์ŠคํŠธ ํŒŒ์ผ์ด ์œ ํšจํ•œ ํŒŒ์ผ ํƒ€์ž…์œผ๋กœ ๊ฐ„์ฃผ๋จ - public boolean isValidFileType(File file) { - String mimeType = getMimeType(String.valueOf(file)); // MIME ํƒ€์ž… ๊ฐ€์ ธ์˜ค๊ธฐ - boolean isValid = false; - if(mimeType.startsWith("image")) { - isValid = true; - } // image๋งŒ ์ผ๋‹จ ํ–ˆ๋Š”๋ฐ ๋ญ ํŒŒ์ผ ํ˜•์‹ ์—ฌ๋Ÿฌ๊ฐœ ํ•ด์•ผ๊ฒ ์ฅฌ - return isValid; - } - - // ํŒŒ์ผ ํฌ๊ธฐ ํ™•์ธ ๋ฉ”์†Œ๋“œ - // ์ฃผ์–ด์ง„ ํŒŒ์ผ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ํŒŒ์ผ ํฌ๊ธฐ๋ฅผ ๋ฐ˜ํ™˜ - public long getFileSize(String filePath) { - File file = new File(filePath); - if (file.exists()) { - return file.length(); // ํŒŒ์ผ ํฌ๊ธฐ ๋ฐ˜ํ™˜ - } else { - System.out.println("ํŒŒ์ผ์ด ์—†์ž–์•„์š”"); // ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ - return 0; - } - } +- **LoginGUI.java** +
+ LoginGUI.java + + ```javascript + package email.gui; + + import javax.swing.*; // Swing ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ์„ ์œ„ํ•œ import + import javax.swing.border.EmptyBorder; + import java.awt.*; + + import java.awt.event.ActionEvent; // ActionEvent ์‚ฌ์šฉ์„ ์œ„ํ•œ import + import java.awt.event.ActionListener; // ActionListener ์ธํ„ฐํŽ˜์ด์Šค ์‚ฌ์šฉ์„ ์œ„ํ•œ import + import java.awt.event.FocusAdapter; + import java.awt.event.FocusEvent; + import java.io.IOException; + + import email.smtp.*; // ํด๋ž˜์Šค import + + public class LoginGUI { + private JFrame frame; // ๋กœ๊ทธ์ธ ์ฐฝ์„ ์œ„ํ•œ JFrame + private JTextField emailField; // ์ด๋ฉ”์ผ ์ž…๋ ฅ ํ•„๋“œ๋ฅผ ์œ„ํ•œ JTextField + private JPasswordField passwordField; // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํ•„๋“œ๋ฅผ ์œ„ํ•œ JPasswordField + private JButton loginButton; // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ์œ„ํ•œ JButton + private JLabel errorLabel; // ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•  JLabel + + + // LoginGUI ์ƒ์„ฑ์ž + public LoginGUI() { + initComponents(); // ์ปดํฌ๋„ŒํŠธ ์ดˆ๊ธฐํ™” ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ + } + + // ๋กœ๊ทธ์ธ ํ™”๋ฉด์„ ํ‘œ์‹œํ•˜๋Š” ๋ฉ”์†Œ๋“œ + public void display() { + frame.setVisible(true); // ํ”„๋ ˆ์ž„์„ ๋ณด์ด๋„๋ก ์„ค์ • + } + + // GUI ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฉ”์†Œ๋“œ + private void initComponents() { + frame = new JFrame("๋กœ๊ทธ์ธ"); // ์ฐฝ ์ด๋ฆ„ ๋ณ€๊ฒฝ + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // ์ฐฝ ๋‹ซ๊ธฐ ๋™์ž‘ ์„ค์ • + frame.setSize(700, 450); // ์ฐฝ ํฌ๊ธฐ ์„ค์ • + frame.setLocationRelativeTo(null); // ๊ฐ€์šด๋ฐ ์ •๋ ฌ + + // E-mail ํ•„๋“œ ์ƒ์„ฑ + emailField = createHintTextField("์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•˜์„ธ์š”", 1, new Color(179, 182, 197), new Color(255,255,255)); // ํžŒํŠธ ํ…์ŠคํŠธ๊ฐ€ ์žˆ๋Š” JTextField ์ƒ์„ฑ + passwordField = createHintPasswordField("๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”", 1, new Color(179, 182, 197), new Color(255,255,255)); + + loginButton = new JButton("Login"); // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ์ƒ์„ฑ + loginButton.setHorizontalAlignment(SwingConstants.CENTER); // ์ค‘์•™ ์ •๋ ฌ + loginButton.setVerticalAlignment(SwingConstants.CENTER); // ์ค‘์•™ ์ •๋ ฌ + + // ๋ฒ„ํŠผ ๋ฐฐ๊ฒฝ์ƒ‰๊ณผ ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + loginButton.setBackground(new Color(204, 122, 136)); // ๋ฐฐ๊ฒฝ์ƒ‰ ์ง€์ • + loginButton.setForeground(Color.WHITE); // ๊ธ€์”จ์ƒ‰ (ํฐ์ƒ‰) + + errorLabel = new JLabel(); // ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•  ๋ ˆ์ด๋ธ” ์ƒ์„ฑ + + loginButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + onLoginButtonClick(); // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์†Œ๋“œ + } + }); + + // ๋ฒ„ํŠผ ์ฃผ์œ„์— ๊ณต๋ฐฑ ์ถ”๊ฐ€ + loginButton.setBorder(BorderFactory.createCompoundBorder( + loginButton.getBorder(), + BorderFactory.createEmptyBorder(10, 80, 10, 80) // ์œ„, ์™ผ์ชฝ, ์•„๋ž˜, ์˜ค๋ฅธ์ชฝ ๊ณต๋ฐฑ ์„ค์ • + )); + + setLayout(); // ๋ ˆ์ด์•„์›ƒ ์„ค์ • + } + + // ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์†Œ๋“œ + private void onLoginButtonClick() { + String email = emailField.getText(); // ์ด๋ฉ”์ผ ์ž…๋ ฅ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ + String password = new String(passwordField.getPassword()); // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ + + // ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋น„์–ด ์žˆ๋Š”์ง€ ํ™•์ธ + if (email.isEmpty() || password.isEmpty()) { + showError("์ด๋ฉ”์ผ ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”."); + return; + } + + // ์ด๋ฉ”์ผ ํ˜•์‹ ๊ฒ€์ฆ + if (!isValidEmail(email)) { + showError("์ด๋ฉ”์ผ ์ฃผ์†Œ ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. \n์˜ˆ์‹œ: ํ™๊ธธ๋™@naver.com ๊ผด๋กœ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."); + return; // ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋ฐ˜ํ™˜ + } + + System.out.println("์ด๋ฉ”์ผ : " + email + " ๋น„๋ฐ€๋ฒˆํ˜ธ : " + password + " ์ž…๋ ฅ์™„๋ฃŒ!"); + // Client ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ + Client client = new Client(email, password); + + // ์ด๋ฉ”์ผ ๋„๋ฉ”์ธ ๊ฒ€์ฆ + if (!client.mailService.isCorrectAddress()) { + showError("์ง€์›ํ•˜์ง€ ์•Š๋Š” ์ด๋ฉ”์ผ ๋„๋ฉ”์ธ์ž…๋‹ˆ๋‹ค. @naver.com์„ ์‚ฌ์šฉํ•˜์„ธ์š”."); + return; // ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋ฐ˜ํ™˜ + } + + // ์ธ์ฆ ์‹œ๋„ + try { + client.mailService.connect(); + // ์ธ์ฆ ์‹œ๋„ + JOptionPane.showMessageDialog(frame, "๋กœ๊ทธ์ธ ์„ฑ๊ณต!"); // ์„ฑ๊ณต ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ + clearFields(); // ํ•„๋“œ ์ดˆ๊ธฐํ™” + frame.dispose(); // ๋กœ๊ทธ์ธ ์ฐฝ ๋‹ซ๊ธฐ + + // SendEmailGUI ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐ ํ‘œ์‹œ + SendEmailGUI sendEmailGUI = new SendEmailGUI(client,this); // SendEmailGUI ์ƒ์„ฑ + sendEmailGUI.display(); // SendEmailGUI ํ‘œ์‹œ + } catch (IOException e) { + showError(e.getMessage()); // ์˜ˆ์™ธ ๋ฉ”์‹œ์ง€๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ + } catch (HeadlessException e) { + e.printStackTrace(); // ์˜ค๋ฅ˜ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค ์ถœ๋ ฅ + showError("์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”."); // ์ผ๋ฐ˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ + } + } + + // ์ด๋ฉ”์ผ ์ฃผ์†Œ์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + private boolean isValidEmail(String email) { + String emailRegex = "^[\\w-\\.]+@[\\w-]+\\.[a-zA-Z]{2,}$"; // ์ด๋ฉ”์ผ ์ •๊ทœ ํ‘œํ˜„์‹ + return email.matches(emailRegex); + } + + // ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํŒ์—…์œผ๋กœ ๋ณด์—ฌ์ฃผ๋Š” ๋ฉ”์†Œ๋“œ + private void showError(String message) { + errorLabel.setText(message); // ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์„ค์ • + JOptionPane.showMessageDialog(frame, message, "์˜ค๋ฅ˜", JOptionPane.ERROR_MESSAGE); // ํŒ์—…์œผ๋กœ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ + } + + // ์ž…๋ ฅ ํ•„๋“œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฉ”์†Œ๋“œ + private void clearFields() { + emailField.setText(""); // ์ด๋ฉ”์ผ ํ•„๋“œ ์ดˆ๊ธฐํ™” + passwordField.setText(""); // ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•„๋“œ ์ดˆ๊ธฐํ™” + } + + + + // ํžŒํŠธ ํ…์ŠคํŠธ๊ฐ€ ์žˆ๋Š” JTextField ์ƒ์„ฑ ๋ฉ”์†Œ๋“œ + private JTextField createHintTextField(String hint, int columns, Color backgroundColor, Color foregroundColor) { + JTextField textField = new JTextField(columns); // JTextField ์ƒ์„ฑ + textField.setBackground(backgroundColor); // ๋ฐฐ๊ฒฝ ์ƒ‰์ƒ ์„ค์ • + textField.setForeground(foregroundColor); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + + + // ํžŒํŠธ ํ…์ŠคํŠธ ์ดˆ๊ธฐํ™” + textField.setText(hint); + textField.setForeground(Color.GRAY); // ํžŒํŠธ ์ƒ‰์ƒ ์„ค์ • + + // ํฌ์ปค์Šค ๋ฆฌ์Šค๋„ˆ ์ถ”๊ฐ€ + textField.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + // ํ•„๋“œ๊ฐ€ ํฌ์ปค์Šค๋ฅผ ๋ฐ›์„ ๋•Œ ํžŒํŠธ ํ…์ŠคํŠธ ์ง€์šฐ๊ธฐ + if (textField.getText().equals(hint)) { + textField.setText(""); + textField.setForeground(Color.BLACK); // ๊ธ€์”จ ์ƒ‰์ƒ ๋ณ€๊ฒฝ + } + } + + @Override + public void focusLost(FocusEvent e) { + // ํ•„๋“œ๊ฐ€ ํฌ์ปค์Šค๋ฅผ ์žƒ์„ ๋•Œ ํžŒํŠธ ํ…์ŠคํŠธ๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด ๋‹ค์‹œ ์„ค์ • + if (textField.getText().isEmpty()) { + textField.setForeground(Color.GRAY); // ํžŒํŠธ ์ƒ‰์ƒ ์„ค์ • + textField.setText(hint); + } + } + }); + + return textField; // ์„ค์ •๋œ JTextField ๋ฐ˜ํ™˜ + } + + // ํžŒํŠธ ํ…์ŠคํŠธ๊ฐ€ ์žˆ๋Š” JPasswordField ์ƒ์„ฑ ๋ฉ”์†Œ๋“œ + private JPasswordField createHintPasswordField(String hint, int columns, Color backgroundColor, Color foregroundColor) { + JPasswordField passwordField = new JPasswordField(columns); // JPasswordField ์ƒ์„ฑ + passwordField.setBackground(backgroundColor); // ๋ฐฐ๊ฒฝ ์ƒ‰์ƒ ์„ค์ • + passwordField.setForeground(foregroundColor); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + + + // ํžŒํŠธ ํ…์ŠคํŠธ ์ดˆ๊ธฐํ™” + passwordField.setText(hint); + passwordField.setForeground(Color.GRAY); // ํžŒํŠธ ์ƒ‰์ƒ ์„ค์ • + + // ํฌ์ปค์Šค ๋ฆฌ์Šค๋„ˆ ์ถ”๊ฐ€ + passwordField.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + // ํ•„๋“œ๊ฐ€ ํฌ์ปค์Šค๋ฅผ ๋ฐ›์„ ๋•Œ ํžŒํŠธ ํ…์ŠคํŠธ ์ง€์šฐ๊ธฐ + if (new String(passwordField.getPassword()).equals(hint)) { + passwordField.setText(""); + passwordField.setForeground(Color.BLACK); // ๊ธ€์”จ ์ƒ‰์ƒ ๋ณ€๊ฒฝ + } + } + + @Override + public void focusLost(FocusEvent e) { + // ํ•„๋“œ๊ฐ€ ํฌ์ปค์Šค๋ฅผ ์žƒ์„ ๋•Œ ํžŒํŠธ ํ…์ŠคํŠธ๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด ๋‹ค์‹œ ์„ค์ • + if (new String(passwordField.getPassword()).isEmpty()) { + passwordField.setForeground(Color.GRAY); // ํžŒํŠธ ์ƒ‰์ƒ ์„ค์ • + passwordField.setText(hint); + } + } + }); + + return passwordField; // ์„ค์ •๋œ JPasswordField ๋ฐ˜ํ™˜ + } + + + // ๋ ˆ์ด์•„์›ƒ์„ ์„ค์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ + private void setLayout() { + JPanel panel = new JPanel(); // ํŒจ๋„ ์ƒ์„ฑ + frame.add(panel); // ํŒจ๋„์„ ํ”„๋ ˆ์ž„์— ์ถ”๊ฐ€ + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); // ์ˆ˜์ง ๋ ˆ์ด์•„์›ƒ ์„ค์ • + panel.setBackground(new Color(56,62,88)); // ๋ฐฐ๊ฒฝ ์ƒ‰ ์„ค์ • + panel.setBorder(new EmptyBorder(40,50,10,50)); // ํŒจ๋”ฉ + + + // ์ƒ๋‹จ ๋ฉ˜ํŠธ + JLabel label_0 = new JLabel("Welcome!"); + Font currentFont = label_0.getFont(); + label_0.setFont(currentFont.deriveFont(36f)); // ํฌ๊ธฐ๋ฅผ 36์œผ๋กœ ์„ค์ • + label_0.setForeground(Color.white); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + panel.add(label_0); + label_0.setBorder(new EmptyBorder(0,0,10,0)); // ์•„๋ž˜ ๊ฐ„๊ฒฉ 10 + + JLabel label_1 = new JLabel("This is Email Sending Program!"); + label_1.setFont(currentFont.deriveFont(20f)); // ํฌ๊ธฐ๋ฅผ 20์œผ๋กœ ์„ค์ • + label_1.setForeground(new Color(177, 181, 193)); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + panel.add(label_1); + label_1.setBorder(new EmptyBorder(0,0,30,0)); // ์•„๋ž˜ ๊ฐ„๊ฒฉ 40 + + JLabel label_2 = new JLabel("Please enter your E-mail address and password."); + label_2.setFont(currentFont.deriveFont(14f)); // ํฌ๊ธฐ๋ฅผ 14์œผ๋กœ ์„ค์ • + label_2.setForeground(new Color(204, 122, 136)); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + panel.add(label_2); + label_2.setBorder(new EmptyBorder(0,0,9,0)); // ์•„๋ž˜ ๊ฐ„๊ฒฉ 9 + + // ์ด๋ฉ”์ผ ๋ ˆ์ด๋ธ” ์ถ”๊ฐ€ + JLabel emailLabel = new JLabel("E-MAIL"); + emailLabel.setFont(currentFont.deriveFont(Font.BOLD,20f)); // ํฌ๊ธฐ๋ฅผ 20์œผ๋กœ ์„ค์ • + emailLabel.setForeground(Color.white); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + panel.add(emailLabel); + emailLabel.setBorder(new EmptyBorder(0,0,11,0)); // ์•„๋ž˜ ๊ฐ„๊ฒฉ 11 + + + panel.add(emailField); // ์ด๋ฉ”์ผ ์ž…๋ ฅ ํ•„๋“œ ์ถ”๊ฐ€ + + + // ์ด๋ฉ”์ผ ๋ ˆ์ด๋ธ” ์ถ”๊ฐ€ + JLabel passwordLabel = new JLabel("PASSWORD"); + passwordLabel.setFont(currentFont.deriveFont(Font.BOLD,20f)); // ํฌ๊ธฐ๋ฅผ 20์œผ๋กœ ์„ค์ • + passwordLabel.setForeground(Color.white); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + panel.add(passwordLabel); + passwordLabel.setBorder(new EmptyBorder(21,0,11,0)); // ์•„๋ž˜ ๊ฐ„๊ฒฉ 11 + + + panel.add(passwordField); // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํ•„๋“œ ์ถ”๊ฐ€ + + // ๋ฒ„ํŠผ ํŒจ๋„ ์ƒ์„ฑ ๋ฐ FlowLayout ์„ค์ • + JPanel buttonPanel = new JPanel(new FlowLayout()); // ๋ฒ„ํŠผ ํŒจ๋„ ์ƒ์„ฑ + buttonPanel.setBackground(new Color(56,62,88)); // ๋ฐฐ๊ฒฝ ์ƒ‰ ์„ค์ • + buttonPanel.add(loginButton); // sendButton ์ถ”๊ฐ€ + + buttonPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT); // ์™ผ์ชฝ ์ •๋ ฌ + + panel.add(buttonPanel); // ๋ฒ„ํŠผ ํŒจ๋„์„ ๋ฉ”์ธ ํŒจ๋„์— ์ถ”๊ฐ€ + + panel.add(Box.createRigidArea(new Dimension(0, 20))); // ์—ฌ๋ฐฑ + //panel.add(loginButton); // ๋ฒ„ํŠผ ์ถ”๊ฐ€ + panel.add(Box.createRigidArea(new Dimension(0, 1))); // ์—ฌ๋ฐฑ + + errorLabel.setForeground(new Color(204,122,136)); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + panel.add(errorLabel); // ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ ˆ์ด๋ธ” ์ถ”๊ฐ€ + + } + } + + + ``` +
- // ํŒŒ์ผ ์ฒจ๋ถ€ ํ›„ ํŒŒ์ผ ๋ชฉ๋ก์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฉ”์†Œ๋“œ - public void manageAttachedFiles() { - // ๋ฆฌ์ŠคํŠธ์— ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜, ์‚ญ์ œํ•˜๊ฑฐ๋‚˜, ์ถœ๋ ฅํ•˜๋Š” ๊ธฐ๋Šฅ ํฌํ•จ ์˜ˆ์ • - // ํ•œ ๋ฉ”์†Œ๋“œ์— ๋„ฃ์ง€ ๋ง๊ณ  ๋‚˜๋ˆŒ๊นŒ? ์ข€ ๊ธธ์–ด์งˆ๊ฑฐ ๊ฐ™๊ธด ํ•จ๋‹ˆ๋‹ค - } - // ํŒŒ์ผ์„ ๋กœ์ปฌ ๋””์Šคํฌ์— ์ €์žฅํ•˜๋Š” ๋ฉ”์†Œ๋“œ - public void saveFileToDisk(File file, String destinationDirectory) throws IOException { - // ํŒŒ์ผ์ด ์œ ํšจํ•œ์ง€ ํ™•์ธ ํ›„ ์ €์žฅ ์˜ˆ์ • - Path destinationPath = Path.of(destinationDirectory, file.getName()); - Files.copy(file.toPath(), destinationPath, StandardCopyOption.REPLACE_EXISTING); - } - } + - GUI component ์ƒ์„ฑ โ†’ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฒ€์ฆ, ์ด๋ฉ”์ผ ๋„๋ฉ”์ธ ๋ฐ ํ˜•์‹ ํ™•์ธ โ†’ ๋กœ๊ทธ์ธ ์„ฑ๊ณตํ•˜๋ฉด `SendEmailGUI` ์‹คํ–‰ + + - `display()` + - main class์—์„œ `display()`๋ฅผ ํ˜ธ์ถœ ์‹œ Login ์ฐฝ ํ‘œ์‹œ + - `initComponents()` + - ๋ชจ๋“  GUI component ์ดˆ๊ธฐํ™” + - Login ๋ฒ„ํŠผ์— ๋Œ€ํ•œ `ActionListener()` ๋“ฑ๋ก โ†’ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ `onLoginButtonClick()` ํ˜ธ์ถœ + - ์ด๋ฉ”์ผ ์ž…๋ ฅ ํ•„๋“œ, ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํ•„๋“œ๋ฅผ ํžŒํŠธ ํ…์ŠคํŠธ๊ฐ€ ์žˆ๋Š” `JTextField` `JPasswordField`๋กœ ์„ค์ • + - `onLoginButtonClick()` + - Login ๋ฒ„ํŠผ ํด๋ฆญ โ†’ ์ด๋ฉ”์ผ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ์—ฌ๋ถ€ ํ™•์ธ, ์ด๋ฉ”์ผ ํ˜•์‹์ด ์œ ํšจํ•œ์ง€ ๊ฒ€์‚ฌ + - **์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ์ด๋ฉ”์ผ ํ˜•์‹, ๋นˆ ์ž…๋ ฅ ๊ฐ’**: `showError()`๋ฅผ ํ†ตํ•ด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ + - **์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ํ˜•์‹**: Client ๊ฐ์ฒด ์ƒ์„ฑ, ์ด๋ฉ”์ผ ์„œ๋น„์Šค ๋„๋ฉ”์ธ์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธ โ†’ ์œ ํšจํ•œ ๋„๋ฉ”์ธ: SMTP ์„œ๋ฒ„์— ์—ฐ๊ฒฐ ์‹œ๋„ โ†’ ์—ฐ๊ฒฐ ์„ฑ๊ณตํ•˜๋ฉด ์ด๋ฉ”์ผ ์ „์†ก GUI ํ™”๋ฉด ์ถœ๋ ฅ + - `createHintTextField()` `createHintPasswordField()` + - ํžŒํŠธ ํ…์ŠคํŠธ๊ฐ€ ํฌํ•จ๋œ `JTextField` `JPasswordField` ์ƒ์„ฑ - ``` -
+ +- **SendEmailGUI.java** +
+ SendEmailGUI.java + + ```javascript + package email.gui; + + import javax.swing.*; + import javax.swing.border.EmptyBorder; + + import java.awt.Color; + import java.awt.Dimension; + import java.awt.FlowLayout; + import java.awt.Font; + import java.awt.event.ActionEvent; + import java.awt.event.ActionListener; + import java.io.File; + import java.io.IOException; + + import java.util.concurrent.*; + + import email.smtp.Client; + import email.smtp.EmailServiceWithNaver; + import email.mime.FileHandler; + + public class SendEmailGUI { + private JFrame frame; + private JTextField recipientField; + private JTextField subjectField; + private JTextArea messageArea; + private JButton sendButton; + private JButton attachButton; + private JButton quitButton; // quit ๋ฒ„ํŠผ ์ถ”๊ฐ€ + private JTextField fileField; + private JLabel statusLabel; + private JLabel errorLabel; + private File attachedFile; + private Client client; + private FileHandler fileHandler; // File handling utility + private ScheduledExecutorService noopScheduler; + private LoginGUI loginGUI; + public SendEmailGUI(Client client,LoginGUI loginGUI) { + this.client = client; + this.fileHandler = new FileHandler(); + this.loginGUI = loginGUI; + initComponents(); + startNoopScheduler(); + } + + public void display() { + frame.setVisible(true); + } + public void unDisplay() { + frame.setVisible(false); + } + + private void initComponents() { + frame = new JFrame("๋ฉ”์ผ ์ „์†ก"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(700, 450); // ์ฐฝ ํฌ๊ธฐ ์„ค์ • + frame.setLocationRelativeTo(null); // Center the frame + + recipientField = new JTextField(15); + subjectField = new JTextField(15); + messageArea = new JTextArea(10, 25); + sendButton = new JButton("Send"); + attachButton = new JButton("Attach File"); + quitButton = new JButton("QUIT"); + fileField = new JTextField(15); + fileField.setEditable(false); + statusLabel = new JLabel(); + errorLabel = new JLabel(); + errorLabel.setForeground(Color.RED); // Set error message color + + // Set colors for the components + + recipientField.setForeground(new Color(56, 62, 88)); + recipientField.setBackground(new Color(179, 182, 197)); + subjectField.setForeground(new Color(56, 62, 88)); + subjectField.setBackground(new Color(179, 182, 197)); + messageArea.setForeground(new Color(56, 62, 88)); + messageArea.setBackground(new Color(179, 182, 197)); + fileField.setForeground(new Color(56, 62, 88)); + fileField.setBackground(new Color(179, 182, 197)); + + recipientField.setForeground(Color.WHITE); + subjectField.setForeground(Color.WHITE); + messageArea.setForeground(Color.WHITE); + fileField.setForeground(Color.WHITE); + + + attachButton.setBackground(new Color(204, 122, 136)); // ๋ฐฐ๊ฒฝ์ƒ‰ ์ง€์ • + attachButton.setForeground(Color.WHITE); + sendButton.setBackground(new Color(204, 122, 136)); // ๋ฐฐ๊ฒฝ์ƒ‰ ์ง€์ • + sendButton.setForeground(Color.WHITE); // White text + quitButton.setBackground(new Color(225, 188, 181)); // ๋ฐฐ๊ฒฝ์ƒ‰ ์ง€์ • + quitButton.setForeground(new Color(56, 62, 88)); // ๊ธ€์ž ์ƒ‰ ์ง€์ • + + sendButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + onSendButtonClick(); + } + }); + + attachButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + onAttachButtonClick(); + } + }); + + quitButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + onQuitButtonClick(); + } + }); + + setLayout(); + } + + private void onSendButtonClick() { + String recipient = recipientField.getText(); + String subject = subjectField.getText(); + String message = messageArea.getText(); + String[] recipients = recipient.split(","); + int maxRetries = 3; // ์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ + int retryCount = 0; + boolean isSent = false; + + if (recipient.isEmpty() || subject.isEmpty() || message.isEmpty()) { + showError("์ด๋ฉ”์ผ ์ฃผ์†Œ, ์ œ๋ชฉ, ๋ฉ”์‹œ์ง€๋ฅผ ๋ชจ๋‘ ์ž…๋ ฅํ•˜์„ธ์š”."); + return; + } + + // ์ด๋ฉ”์ผ ํ˜•์‹ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (!isValidEmailFormat(recipients)) { + showError("์œ ํšจํ•œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”."); + return; // ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ „์†ก ์‹œ๋„ํ•˜์ง€ ์•Š์Œ + } + + while (retryCount < maxRetries && !isSent) { + try { + EmailServiceWithNaver emailService = client.mailService; + if (emailService.isCorrectAddress()) { + emailService.connect(); + for (String mailRec : recipients) { + if (attachedFile != null && attachedFile.exists()) { + File[] attachments = {attachedFile}; + emailService.sendEmail(mailRec.trim(), subject, message, attachments); // ์ฒจ๋ถ€ ํŒŒ์ผ ์žˆ๋Š” ๊ฒฝ์šฐ + } else { + emailService.sendEmail(mailRec.trim(), subject, message, null); // ์ฒจ๋ถ€ ํŒŒ์ผ ์—†๋Š” ๊ฒฝ์šฐ + } + } + JOptionPane.showMessageDialog(frame, "์ด๋ฉ”์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", "์ „์†ก ์™„๋ฃŒ", JOptionPane.INFORMATION_MESSAGE); + statusLabel.setText("์ด๋ฉ”์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); + clearFields(); + isSent = true; // ์ „์†ก ์„ฑ๊ณต ์‹œ true๋กœ ์„ค์ • + } + + } catch (IOException e) { + retryCount++; // ์‹คํŒจ ์‹œ ์žฌ์‹œ๋„ ํšŸ์ˆ˜ ์ฆ๊ฐ€ + showError("์ „์†ก ์˜ค๋ฅ˜: " + e.getMessage() + " ์žฌ์‹œ๋„ ์ค‘... (" + retryCount + "/" + maxRetries + ")"); + } + } + + if (!isSent) { + showError("์ด๋ฉ”์ผ ์ „์†ก ์‹คํŒจ: ์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค."); + } + } + + // ์ด๋ฉ”์ผ ํ˜•์‹ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋ฉ”์„œ๋“œ + private boolean isValidEmailFormat(String[] emails) { + String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$"; // ์ด๋ฉ”์ผ ํ˜•์‹ ์ •๊ทœ์‹ + for (String email : emails) { + if (!email.trim().matches(emailRegex)) + return false; // ์ด๋ฉ”์ผ ํ˜•์‹์ด ์œ ํšจํ•˜์ง€ ์•Š์œผ๋ฉด false ๋ฐ˜ํ™˜ + + // Show success message + JOptionPane.showMessageDialog(frame, "์ด๋ฉ”์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", "์ „์†ก ์™„๋ฃŒ", JOptionPane.INFORMATION_MESSAGE); + statusLabel.setText("์ด๋ฉ”์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); + clearFields(); + + + } + return true; + } + + + private void onAttachButtonClick() { + JFileChooser fileChooser = new JFileChooser(); + int result = fileChooser.showOpenDialog(frame); + + if (result == JFileChooser.APPROVE_OPTION) { + File selectedFile = fileChooser.getSelectedFile(); + if (fileHandler.isValidFileType(selectedFile)) { + attachedFile = selectedFile; + fileField.setText(attachedFile.getAbsolutePath()); + statusLabel.setText("์ฒจ๋ถ€ ํŒŒ์ผ: " + attachedFile.getName()); + } else { + showError("์œ ํšจํ•˜์ง€ ์•Š์€ ํŒŒ์ผ ํ˜•์‹์ž…๋‹ˆ๋‹ค."); + } + } + } + + private void onQuitButtonClick() { + try { + EmailServiceWithNaver emailService = client.mailService; + + stopNoopScheduler(); + // ์„œ๋ฒ„์— QUIT ๋ช…๋ น์„ ๋ณด๋‚ด๊ณ  ์—ฐ๊ฒฐ ์ข…๋ฃŒ + emailService.Quit(); + + // ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ + JOptionPane.showMessageDialog(frame, "์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.", "์ข…๋ฃŒ", JOptionPane.INFORMATION_MESSAGE); + + // ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ + frame.dispose(); + } catch (IOException e) { + showError("์—ฐ๊ฒฐ ์ข…๋ฃŒ ์˜ค๋ฅ˜: " + e.getMessage()); + } + } + + + // ์ฃผ๊ธฐ์ ์œผ๋กœ NOOP ๋ช…๋ น์„ ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ ์Šค์ผ€์ค„๋Ÿฌ ์„ค์ • + private void startNoopScheduler() { + if (noopScheduler != null && !noopScheduler.isShutdown()) { + System.out.println("NOOP ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ์ด๋ฏธ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค."); + return; + } + noopScheduler = Executors.newSingleThreadScheduledExecutor(); + noopScheduler.scheduleAtFixedRate(() -> { + try { + client.mailService.sendNoop(); // NOOP ๋ช…๋ น ์ „์†ก + System.out.println("NOOP ๋ช…๋ น์ด ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); + } catch (IOException e) { + showError("NOOP ๋ช…๋ น ์ „์†ก ์˜ค๋ฅ˜: " + e.getMessage()); + stopNoopScheduler(); // ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์Šค์ผ€์ค„๋Ÿฌ ์ค‘์ง€ + unDisplay(); + loginGUI.display(); + } + }, 0, 9, TimeUnit.SECONDS); // 9์ดˆ๋งˆ๋‹ค NOOP ์ „์†ก + } + + + // ์Šค์ผ€์ค„๋Ÿฌ ์ค‘์ง€ + private void stopNoopScheduler() { + if (noopScheduler != null && !noopScheduler.isShutdown()) { + noopScheduler.shutdown(); + } + } + + private void showError(String message) { + errorLabel.setText(message); + JOptionPane.showMessageDialog(frame, message, "์˜ค๋ฅ˜", JOptionPane.ERROR_MESSAGE); + } + + private void clearFields() { + recipientField.setText(""); + subjectField.setText(""); + messageArea.setText(""); + fileField.setText(""); + statusLabel.setText(""); + errorLabel.setText(""); + attachedFile = null; // Reset attached file + } + + private void setLayout() { + JPanel panel = new JPanel(); + frame.add(panel); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBackground(new Color(56,62,88)); // ๋ฐฐ๊ฒฝ ์ƒ‰ ์„ค์ • + panel.setBorder(new EmptyBorder(40,50,10,50)); + + + JLabel toLabel = new JLabel("To."); + Font currentFont = toLabel.getFont(); + toLabel.setFont(currentFont.deriveFont(Font.BOLD,13f)); // ํฌ๊ธฐ๋ฅผ 13์œผ๋กœ ์„ค์ • + toLabel.setForeground(Color.white); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + toLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT); // ์™ผ์ชฝ ์ •๋ ฌ + panel.add(toLabel); + panel.add(Box.createRigidArea(new Dimension(0, 5))); // ์—ฌ๋ฐฑ + + panel.add(recipientField); + panel.add(Box.createRigidArea(new Dimension(0, 9))); // ์—ฌ๋ฐฑ + + JLabel subjectLabel = new JLabel("Subject."); + subjectLabel.setFont(currentFont.deriveFont(Font.BOLD,13f)); // ํฌ๊ธฐ๋ฅผ 13์œผ๋กœ ์„ค์ • + subjectLabel.setForeground(Color.white); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + subjectLabel.setHorizontalAlignment(SwingConstants.LEFT); // ์™ผ์ชฝ ์ •๋ ฌ + panel.add(subjectLabel); + panel.add(Box.createRigidArea(new Dimension(0, 5))); // ์—ฌ๋ฐฑ + + panel.add(subjectField); + panel.add(Box.createRigidArea(new Dimension(0, 9))); // ์—ฌ๋ฐฑ + + JLabel messageLabel = new JLabel("Message."); + messageLabel.setFont(currentFont.deriveFont(Font.BOLD,13f)); // ํฌ๊ธฐ๋ฅผ 13์œผ๋กœ ์„ค์ • + messageLabel.setForeground(Color.white); // ๊ธ€์”จ ์ƒ‰์ƒ ์„ค์ • + panel.add(messageLabel); + panel.add(Box.createRigidArea(new Dimension(0, 5))); // ์—ฌ๋ฐฑ + + panel.add(new JScrollPane(messageArea)); + + panel.add(Box.createRigidArea(new Dimension(0, 9))); + + panel.add(attachButton); // ํŒŒ์ผ ์ฒจ๋ถ€ ๋ฒ„ํŠผ + + panel.add(Box.createRigidArea(new Dimension(0, 9))); // ์—ฌ๋ฐฑ ์ถ”๊ฐ€ + + panel.add(fileField); + + panel.add(Box.createRigidArea(new Dimension(0, 10))); // ์—ฌ๋ฐฑ ์ถ”๊ฐ€ + + panel.add(statusLabel); + panel.add(errorLabel); + + // ๋ฒ„ํŠผ ํŒจ๋„ ์ƒ์„ฑ ๋ฐ FlowLayout ์„ค์ • + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); // ๋ฒ„ํŠผ ํŒจ๋„ ์ƒ์„ฑ + buttonPanel.setBackground(new Color(56,62,88)); // ๋ฐฐ๊ฒฝ ์ƒ‰ ์„ค์ • + buttonPanel.add(sendButton); // sendButton ์ถ”๊ฐ€ + buttonPanel.add(quitButton); // quitButton ์ถ”๊ฐ€ + buttonPanel.setAlignmentX(JPanel.LEFT_ALIGNMENT); // ์™ผ์ชฝ ์ •๋ ฌ + + panel.add(buttonPanel); // ๋ฒ„ํŠผ ํŒจ๋„์„ ๋ฉ”์ธ ํŒจ๋„์— ์ถ”๊ฐ€ + + + } + } + ``` +
+ + - ์ด๋ฉ”์ผ ์ž‘์„ฑ ๋ฐ ์ „์†กํ•˜๋Š” GUI ์ œ๊ณต, ์ฒจ๋ถ€ ํŒŒ์ผ ๊ธฐ๋Šฅ, ์ฃผ๊ธฐ์ ์ธ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์œ ์ง€ ๊ธฐ๋Šฅ + + - `SendEmailGUI` + - Client์™€ LoginGUI ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ›์•„์„œ ์ด๋ฉ”์ผ ์ „์†ก์— ์‚ฌ์šฉ, LoginGUI๋ฅผ ํ†ตํ•ด ์žฌ๋กœ๊ทธ์ธ์„ ์ง€์› + - `initComponents()` ํ˜ธ์ถœ โ†’ ๋ชจ๋“  component ์ดˆ๊ธฐํ™” + - `startNoopScheduler()` โ†’ ์„œ๋ฒ„ ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•œ NOOP ๋ช…๋ น์„ 9์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ ์ „์†ก + - `button` + - `onSendButtonClick()`: ์ˆ˜์‹ ์ž, ์ œ๋ชฉ, ๋ฉ”์‹œ์ง€ ํ™•์ธ โ†’ SMTP ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•˜์—ฌ ์ด๋ฉ”์ผ ์ „์†ก (์ „์†ก ์‹คํŒจ ์‹œ ์ตœ๋Œ€ 3๋ฒˆ๊นŒ์ง€ ์žฌ์‹œ๋„ ๊ฐ€๋Šฅ) + - `onAttachButtonClick()`: `JFileChooser`์„ ํ†ตํ•ด ํŒŒ์ผ ์„ ํƒ โ†’ `fileHandler.isValidFileType()`๋กœ ํŒŒ์ผ ํ˜•์‹ ๊ฒ€์‚ฌ โ†’ ์œ ํšจํ•œ ํŒŒ์ผ์ด๋ฉด `attachedFile`์— ์ €์žฅ + - `onQuitButtonClick()`: ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์ข…๋ฃŒ, NOOP ์Šค์ผ€์ค„๋Ÿฌ ์ค‘์ง€, ์ฐฝ ๋‹ซ์€ ํ›„ `LoginGUI` ์ฐฝ ํ‘œ์‹œ -
- MimeMessageBuilder.java - - ```javascript - package email.mime; - -import javax.mail.*; // javax.mail ํŒจํ‚ค์ง€์—์„œ ํ•„์š”ํ•œ ํด๋ž˜์Šค๋“ค์„ ์ž„ํฌํŠธ -import javax.mail.internet.*; // ์ด๋ฉ”์ผ ์ „์†ก์„ ์œ„ํ•œ ์ธํ„ฐ๋„ท ๋ฉ”์ผ ํด๋ž˜์Šค๋ฅผ ์ž„ํฌํŠธ -import java.util.Properties; // ์ด๋ฉ”์ผ ์ „์†ก์— ํ•„์š”ํ•œ ์„ค์ • ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค - -public class MimeMessageBuilder { - private Session session; // ๋ฉ”์ผ ์„ธ์…˜์„ ์œ„ํ•œ ๊ฐ์ฒด - private MimeMessage message; // MIME ๋ฉ”์‹œ์ง€๋ฅผ ์œ„ํ•œ ๊ฐ์ฒด - - // MimeMessageBuilder ์ƒ์„ฑ์ž - // ์ด๋ฉ”์ผ ์„ธ์…˜์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ๋ฉ”์‹œ์ง€ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ - public MimeMessageBuilder(String smtpHost, String smtpPort, String email, String password) { - Properties properties = new Properties(); // ๋ฉ”์ผ ์„œ๋ฒ„ ์—ฐ๊ฒฐ์„ ์œ„ํ•œ ์„ค์ • - properties.put("mail.smtp.host", smtpHost); // SMTP ์„œ๋ฒ„ ํ˜ธ์ŠคํŠธ ์„ค์ • - properties.put("mail.smtp.port", smtpPort); // SMTP ์„œ๋ฒ„ ํฌํŠธ ์„ค์ • - properties.put("mail.smtp.auth", "true"); // SMTP ์ธ์ฆ ์‚ฌ์šฉ ์„ค์ • - properties.put("mail.smtp.starttls.enable", "true"); // TLS ์‚ฌ์šฉ ์„ค์ • - - session = Session.getInstance(properties, new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(email, password); // ์ด๋ฉ”์ผ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ์ธ์ฆ - } - }); - - try { - message = new MimeMessage(session); // ์„ธ์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ MIME ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ - } catch (MessagingException e) { - e.printStackTrace(); // ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ ์‹œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ถœ๋ ฅ - } - } - - // ์ˆ˜์‹ ์ž ์ด๋ฉ”์ผ ์ฃผ์†Œ ์„ค์ • ๋ฉ”์†Œ๋“œ - // ์ˆ˜์‹ ์ž์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ถ”๊ฐ€ - public void setRecipient(String recipient) throws MessagingException { - message.addRecipient(Message.RecipientType.TO, new InternetAddress(recipient)); // ์ˆ˜์‹ ์ž ์ถ”๊ฐ€ - } - - // ์ด๋ฉ”์ผ ์ œ๋ชฉ ์„ค์ • ๋ฉ”์†Œ๋“œ - // ์ด๋ฉ”์ผ ์ œ๋ชฉ์„ ์„ค์ • - public void setSubject(String subject) throws MessagingException { - message.setSubject(subject); // ์ œ๋ชฉ ์„ค์ • - } - - // ์ด๋ฉ”์ผ ๋ณธ๋ฌธ ์„ค์ • ๋ฉ”์†Œ๋“œ - // ์ด๋ฉ”์ผ ๋‚ด์šฉ์„ ์„ค์ • (HTML ํ˜•์‹ ์ง€์›) - public void setBody(String body) throws MessagingException { - message.setContent(body, "text/html; charset=utf-8"); // ๋ณธ๋ฌธ ๋‚ด์šฉ ์„ค์ • - } - - // ์ด๋ฉ”์ผ ์ฒจ๋ถ€ ํŒŒ์ผ ์ถ”๊ฐ€ ๋ฉ”์†Œ๋“œ - // ์ฒจ๋ถ€ํ•  ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ๋ฐ›์•„ MIME ๋ฉ”์‹œ์ง€์— ์ฒจ๋ถ€ - public void addAttachment(String filePath) throws MessagingException { - MimeBodyPart messageBodyPart = new MimeBodyPart(); // ์ฒจ๋ถ€ ํŒŒ์ผ์„ ์œ„ํ•œ ๋ฐ”๋”” ํŒŒํŠธ ์ƒ์„ฑ - messageBodyPart.setFileName(filePath); // ํŒŒ์ผ ์ด๋ฆ„ ์„ค์ • - - MimeMultipart multipart = new MimeMultipart(); // ์—ฌ๋Ÿฌ ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ์„ฑ๋œ MIME ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ - multipart.addBodyPart(messageBodyPart); // ๋ฐ”๋”” ํŒŒํŠธ ์ถ”๊ฐ€ - message.setContent(multipart); // ๋ฉ”์‹œ์ง€์— MIME ๋ฉ€ํ‹ฐํŒŒํŠธ ์„ค์ • - } + +### 2. *email.mime* +- **FileHandler.java** +
+ FileHandler.java + + ```javascript + package email.mime; + + import java.io.*; + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.Paths; + import java.nio.file.StandardCopyOption; + public class FileHandler { + + public void attachFile(String filePath) { + File file = new File(filePath); + if (file.exists()) { + if (isValidFileType(file)) { + System.out.println(file.getName() + " ํŒŒ์ผ์ด ์ฒจ๋ถ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); + } else { + System.out.println("์œ ํšจํ•˜์ง€ ์•Š์€ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค."); + } + } else { + System.out.println("ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } + + public String getMimeType(String filePath) { + Path path = Paths.get(filePath); + try { + return Files.probeContentType(path); + } catch (IOException e) { + System.err.println("MIME ํƒ€์ž… ํƒ์ง€ ์˜ค๋ฅ˜: " + e.getMessage()); + return "์•Œ ์ˆ˜ ์—†๋Š” MIME ํƒ€์ž…"; + } + } + + public boolean isValidFileType(File file) { + String mimeType = getMimeType(file.getAbsolutePath()); + return mimeType.startsWith("image") || mimeType.equals("application/pdf") || mimeType.startsWith("text"); + } + + public long getFileSize(String filePath) { + File file = new File(filePath); + if (file.exists()) { + return file.length(); + } else { + System.out.println("ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + return 0; + } + } + + public void saveFileToDisk(File file, String destinationDirectory) { + Path destinationPath = Paths.get(destinationDirectory, file.getName()); + try { + Files.copy(file.toPath(), destinationPath, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + System.err.println("ํŒŒ์ผ ์ €์žฅ ์˜ค๋ฅ˜: " + e.getMessage()); + } + } + + public String readFile(String filePath) { + StringBuilder contentBuilder = new StringBuilder(); + try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { + String line; + while ((line = br.readLine()) != null) { + contentBuilder.append(line).append(System.lineSeparator()); + } + } catch (IOException e) { + System.err.println("ํŒŒ์ผ ์ฝ๊ธฐ ์˜ค๋ฅ˜: " + e.getMessage()); + } + return contentBuilder.toString(); + } + } + ``` +
+ + - ํŒŒ์ผ ์ฒจ๋ถ€, MIME ํƒ€์ž… ํ™•์ธ, ํŒŒ์ผ ํฌ๊ธฐ ์ธก์ •, ํŒŒ์ผ ์ €์žฅ, ํŒŒ์ผ ์ฝ๊ธฐ ๊ธฐ๋Šฅ + + - `attachFile` + - ์ง€์ • ํŒŒ์ผ๊ฒฝ๋กœ์˜ ํŒŒ์ผ์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ, ์œ ํšจํ•œ ํŒŒ์ผ ํ˜•์‹์ธ์ง€ ๊ฒ€์‚ฌ + - ์œ ํšจํ•œ ํ˜•์‹์˜ ํŒŒ์ผ: ํŒŒ์ผ์ด ์ฒจ๋ถ€๋˜์—ˆ๋‹ค๋Š” ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ + - ์œ ํšจํ•˜์ง€ ์•Š์€ ํ˜•์‹์˜ ํŒŒ์ผ: "์œ ํšจํ•˜์ง€ ์•Š์€ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค" ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ + - `getMimeType` + - `Files.probeContentType()` ํ†ตํ•ด ํŒŒ์ผ ๊ฒฝ๋กœ๋กœ๋ถ€ํ„ฐ MIME ํƒ€์ž… ์ถ”์ถœ + - ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ "์•Œ ์ˆ˜ ์—†๋Š” MIME ํƒ€์ž…" ๋ฐ˜ํ™˜ + - `isValidFileType` + - MIME ํƒ€์ž…์ด ์ด๋ฏธ์ง€, PDF, ํ…์ŠคํŠธ ํŒŒ์ผ์ธ์ง€ ํ™•์ธ โ†’ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌ + - ์œ ํšจํ•œ ํ˜•์‹: true ๋ฐ˜ํ™˜ + - ์œ ํšจํ•˜์ง€ ์•Š์€ ํ˜•์‹: false ๋ฐ˜ํ™˜ + - `getFileSize` + - ์ง€์ •๋œ ํŒŒ์ผ์˜ ํฌ๊ธฐ๋ฅผ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๋ฐ˜ํ™˜ + - ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด 0 ๋ฐ˜ํ™˜, "ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค" ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ + - `saveFileToDisk` + - ํŒŒ์ผ์„ ์ง€์ •๋œ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋ณต์‚ฌํ•˜์—ฌ ์ €์žฅ + - ๋™์ผํ•œ ์ด๋ฆ„์˜ ํŒŒ์ผ์ด ์žˆ์„ ๊ฒฝ์šฐ: `StandardCopyOption.REPLACE_EXISTING`์„ ์‚ฌ์šฉํ•ด ๊ธฐ์กด ํŒŒ์ผ์„ ๋ฎ์Œ + - `readFile` + - `BufferedReader`๋กœ ํŒŒ์ผ์„ ํ•œ ์ค„์”ฉ ์ฝ๊ธฐ โ†’ `StringBuilder`์— ๋‚ด์šฉ ์ €์žฅ โ†’ ๋งˆ์ง€๋ง‰์— ๋ฐ˜ํ™˜ - // MIME ๋ฉ”์‹œ์ง€ ์ „์†ก ๋ฉ”์†Œ๋“œ - // ์ƒ์„ฑ๋œ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†ก - public void send() throws MessagingException { - Transport.send(message); // ์ด๋ฉ”์ผ ์ „์†ก - System.out.println("์ด๋ฉ”์ผ์ด ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); // ์ „์†ก ์„ฑ๊ณต ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ - } -} - ``` -
+ +- **MimeMessageBuilder.java** +
+ MimeMessageBuilder.java + + ```javascript + package email.mime; + + import java.io.*; + import java.nio.file.Files; + import java.util.Base64; + + public class MimeMessageBuilder { + private String boundary; + private String from; + private String to; + private String subject; + private String body; + private File[] attachments; + + public MimeMessageBuilder(String from, String to, String subject, String body, File[] attachments) { + this.from = from; + this.to = to; + this.subject = subject; + this.body = body; + this.attachments = attachments; + this.boundary = "----=_MIME_BOUNDARY_" + System.currentTimeMillis(); + } + + // From ํ—ค๋” + private String createFromHeader() { + return "From: " + from + "\r\n"; + } + + // To ํ—ค๋” + private String createToHeader() { + return "To: " + to + "\r\n"; + } + + // Subject ํ—ค๋” + private String createSubjectHeader() { + return "Subject: " + subject + "\r\n"; + } + + // MIME ๋ณธ๋ฌธ + private String createMimeBody() { + StringBuilder mimeBody = new StringBuilder(); + mimeBody.append("Content-Type: text/plain; charset=UTF-8\r\n"); + mimeBody.append("Content-Transfer-Encoding: 7bit\r\n"); + mimeBody.append("\r\n"); + mimeBody.append(body).append("\r\n"); + return mimeBody.toString(); + } + + // ์ฒจ๋ถ€ ํŒŒ์ผ์„ MIME ํŒŒํŠธ๋กœ ์ธ์ฝ”๋”ฉ + private String createMimeAttachment(File file) throws IOException { + StringBuilder mimeAttachment = new StringBuilder(); + mimeAttachment.append("Content-Type: application/octet-stream; name=\"").append(file.getName()).append("\"\r\n"); + mimeAttachment.append("Content-Transfer-Encoding: base64\r\n"); + mimeAttachment.append("Content-Disposition: attachment; filename=\"").append(file.getName()).append("\"\r\n"); + mimeAttachment.append("\r\n"); + mimeAttachment.append(encodeFileToBase64(file)).append("\r\n"); + return mimeAttachment.toString(); + } + + // Boundary ์ถ”๊ฐ€ + private String createMimeBoundary() { + return "--" + boundary + "\r\n"; + } + + // Base64 ์ธ์ฝ”๋”ฉ + private String encodeFileToBase64(File file) throws IOException { + byte[] fileContent = Files.readAllBytes(file.toPath()); + return Base64.getEncoder().encodeToString(fileContent); + } + + // ์ตœ์ข… MIME ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ + public String build() throws IOException { + StringBuilder mimeMessage = new StringBuilder(); + + mimeMessage.append(createFromHeader()); + mimeMessage.append(createToHeader()); + mimeMessage.append(createSubjectHeader()); + mimeMessage.append("MIME-Version: 1.0\r\n"); + mimeMessage.append("Content-Type: multipart/mixed; boundary=\"").append(boundary).append("\"\r\n"); + mimeMessage.append("\r\n"); + + // ๋ณธ๋ฌธ ์ถ”๊ฐ€ + mimeMessage.append(createMimeBoundary()); + mimeMessage.append(createMimeBody()); + + // ์ฒจ๋ถ€ ํŒŒ์ผ ์ถ”๊ฐ€ + if (attachments != null) { + for (File file : attachments) { + mimeMessage.append(createMimeBoundary()); + mimeMessage.append(createMimeAttachment(file)); + } + } + + // ๋ฉ”์‹œ์ง€ ์ข…๋ฃŒ + mimeMessage.append("--").append(boundary).append("--\r\n"); + + return mimeMessage.toString(); + } + } + ``` +
+ + - ํ—ค๋” ์ƒ์„ฑ, ์ด๋ฉ”์ผ ๋ณธ๋ฌธ๊ณผ ์ฒจ๋ถ€ ํŒŒ์ผ์„ MIME ํ˜•์‹์œผ๋กœ ๊ตฌ์„ฑ, ์™„์„ฑ๋œ MIME ๋ฉ”์‹œ์ง€๋ฅผ ๋ฌธ์ž์—ด ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜ + + - `createFromHeader()` `createToHeader()` `createSubjectHeader()` + - ๊ฐ๊ฐ ๋ฐœ์‹ ์ž, ์ˆ˜์‹ ์ž, ์ œ๋ชฉ ํ•„๋“œ์˜ ํ—ค๋” ์ƒ์„ฑ + - `createMimeBody` + - ์ด๋ฉ”์ผ ๋ณธ๋ฌธ์„ MIME ํ˜•์‹์œผ๋กœ ์ž‘์„ฑ + - ๋ณธ๋ฌธ์€ ํ…์ŠคํŠธ๋กœ ์„ค์ •, `text/plain` `charset`์€ UTF-8๋กœ ์ง€์ • + - `createMimeAttachment` + - ์ฒจ๋ถ€ ํŒŒ์ผ์„ base64๋กœ ์ธ์ฝ”๋”ฉํ•˜์—ฌ MIME ํ˜•์‹์œผ๋กœ ๊ตฌ์„ฑ + - `Content-Transfer-Encoding: base64`: ์ฒจ๋ถ€ ํŒŒ์ผ ๋‚ด์šฉ์„ Base64๋กœ ์ธ์ฝ”๋”ฉ + - `encodeFileToBase64` + - ์ฒจ๋ถ€ ํŒŒ์ผ ๋ฐ”์ดํŠธ ๋ฐ์ดํ„ฐ๋ฅผ Base64๋กœ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ๋ฐ˜ํ™˜ + - SMTP๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ๋„๋ก ASCII ๋ฌธ์ž์—ด ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ + - `build` + - `createMimeBoundary()`: ๋ณธ๋ฌธ๊ณผ ์ฒจ๋ถ€ ํŒŒ์ผ ๊ตฌ๋ถ„ + - ์ฒจ๋ถ€ ํŒŒ์ผ์ด ์žˆ์„ ๊ฒฝ์šฐ ์ด๋ฅผ MIME ํŒŒํŠธ๋กœ ์ถ”๊ฐ€ -- `FileHandler.java`: ํŒŒ์ผ ์ฒจ๋ถ€ ์ฒ˜๋ฆฌ ๋ฐ ํŒŒ์ผ ๊ด€๋ จ ์ž‘์—… -- `MimeMessageBuilder.java`: MIME ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ ๋ฐ ๊ด€๋ จ ์ฒ˜๋ฆฌ + +### 3. *email.smtp* -### 3. `email.smtp` -
- Auth.java - -```javascript - -``` -
- -
- Client.java - -```javascript -package email.smtp; - -import java.io.*; -import java.net.Socket; -import java.util.Base64; -import email.mime.FileHandler; -import email.smtp.Auth; - -public class Client { - private Auth auth; // ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด - private FileHandler fileHandler; // ํŒŒ์ผ ์ฒ˜๋ฆฌ - - // Client ์ƒ์„ฑ์ž - public Client(Auth auth, FileHandler fileHandler) { - this.auth = auth; // ์ธ์ฆ ๊ฐ์ฒด ์„ค์ • - this.fileHandler = fileHandler; // ํŒŒ์ผ ์ฒ˜๋ฆฌ ๊ฐ์ฒด ์„ค์ • +- **Client.java** +
+ Client.java + + ```javascript + package email.smtp; + + public class Client { + + public EmailServiceWithNaver mailService; + + public Client(String mail, String password) { + if (mail.endsWith("@naver.com")) { + mailService=new EmailServiceWithNaver(mail,password,"smtp.naver.com",465); + + }else + mailService=new EmailServiceWithNaver(mail,password,null,-1); + } } + + ``` +
+ + * ์‚ฌ์šฉ์ž์—๊ฒŒ ์ด๋ฉ”์ผ ์ฃผ์†Œ์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฐ›์•„ ํ•ด๋‹น ์ด๋ฉ”์ผ ์„œ๋น„์Šค์— ๋งž๋Š” `EmailServiceWithNaver` ๊ฐ์ฒด ์ดˆ๊ธฐํ™” - // ์ด๋ฉ”์ผ ์ „์†ก ๋ฉ”์†Œ๋“œ - // ์ด๋ฉ”์ผ ์ž‘์„ฑํ•œ ๋‚ด์šฉ์„ ๋ฐ›์•„์™€์„œ ์ „์†กํ•˜๋Š” ๋ฉ”์†Œ๋“œ ์ž…๋‹ˆ๋‹ค. - // Auth class ์ฐธ๊ณ ํ•˜๋ฉด์„œ ์ž‘์„ฑํ–ˆ๋Š”๋ฐ private ๋ณ€์ˆ˜๋ฅผ public์œผ๋กœ ๋ฐ”๊พธ์„œ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.. - public boolean sendEmail(String recipient, String subject, String messageBody, String filePath) { - // ์ง€์›ํ•˜๋Š” ์ด๋ฉ”์ผ ํ˜•์‹์ธ์ง€ ๊ตฌ๋ถ„ - if (!auth.authenticate()) { // ์ธ์ฆ ๋˜์ง€ ์•Š์•˜์œผ๋ฉด false ๋ฐ˜ํ™˜ - return false; - } - - // ์†Œ์ผ“ ์„ค์ • - try (Socket socket = new Socket(auth.smtpServer, auth.port); // SMTP ์„œ๋ฒ„์— ์†Œ์ผ“ ์—ฐ๊ฒฐ - BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); // ์„œ๋ฒ„ ์‘๋‹ต ์ฝ๊ธฐ - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) { // ์„œ๋ฒ„์— - // ๋ช…๋ น์–ด - // ์“ฐ๊ธฐ - - // ์„œ๋ฒ„ ์‘๋‹ต ํ™•์ธ - readResponse(reader); - - // EHLO ๋ช…๋ น - SMTP ์„œ๋ฒ„ ํ†ต์‹  ์‹œ์ž‘ - sendCommand(writer, "EHLO " + auth.smtpServer); - readResponse(reader); - - // SMTP ์ธ์ฆ - sendCommand(writer, "AUTH LOGIN"); // ์ธ์ฆ ์‹œ์ž‘ - readResponse(reader); - - // ์ผ๋‹จ ์ด๋ฉ”์ผ,๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฝ”๋”ฉ ์ž‘์„ฑํ•˜๊ธฐ๋Š”ํ–ˆ๋Š”๋ฐ MIME ์ด๋‚˜ FileHandler ์—์„œ ์ฒ˜๋ฆฌํ•ด์ฃผ์‹œ๋ฉด ์ฝ”๋“œ ๋‹ค์‹œ ๋ฐ”๊พธ๋ฉด ๋ ๋“ฏํ•ฉ๋‹ˆ๋‹ค. - sendCommand(writer, Base64.getEncoder().encodeToString(auth.email.getBytes())); // ์ด๋ฉ”์ผ ์ฃผ์†Œ ์ธ์ฝ”๋”ฉ ์ „์†ก - readResponse(reader); - sendCommand(writer, Base64.getEncoder().encodeToString(auth.password.getBytes())); // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฝ”๋”ฉ ์ „์†ก - readResponse(reader); - - // ์†ก์‹ ์ž์™€ ์ˆ˜์‹ ์ž ์„ค์ • - sendCommand(writer, "MAIL FROM:<" + auth.email + ">"); // ์†ก์‹ ์ž ์„ค์ • - readResponse(reader); - sendCommand(writer, "RCPT TO:<" + recipient + ">"); // ์ˆ˜์‹ ์ž ์„ค์ • - readResponse(reader); - - // ๋ฐ์ดํ„ฐ ์ „์†ก ์‹œ์ž‘ - sendCommand(writer, "DATA"); // ๋ฐ์ดํ„ฐ ์ „์†ก - readResponse(reader); + * `mailService` + - `EmailServiceWithNaver`์˜ ์ธ์Šคํ„ด์Šค + - ์‹ค์ œ ์ด๋ฉ”์ผ ์ „์†ก ๋ฐ SMTP ์—ฐ๊ฒฐ ๊ธฐ๋Šฅ ์ˆ˜ํ–‰ + + * `Client` + - mail์ด `@naver.com`์œผ๋กœ ๋๋‚˜๋Š”์ง€ ํ™•์ธ + - `@naver.com` ๋„๋ฉ”์ธ์ธ ๊ฒฝ์šฐ: `mailService`๊ฐ€ `smtp.naver.com` ์„œ๋ฒ„๋กœ ์—ฐ๊ฒฐ + - `@naver.com` ๋„๋ฉ”์ธ์ด ์•„๋‹Œ ๊ฒฝ์šฐ: `EmailServiceWithNaver` ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ, SMTP ์„œ๋ฒ„ ์ •๋ณด `null`๊ณผ `-1`๋กœ ์„ค์ • โ†’ ์—ฐ๊ฒฐ X - // ์ด๋ฉ”์ผ ๋ณธ๋ฌธ ์ž‘์„ฑ - writer.write("Subject: " + subject + "\r\n"); // ์ œ๋ชฉ - writer.write("From: " + auth.email + "\r\n"); // ์†ก์‹ ์ž - writer.write("To: " + recipient + "\r\n"); // ์ˆ˜์‹ ์ž - writer.write("MIME-Version: 1.0\r\n"); // MIME ๋ฒ„์ „ 1.0์œผ๋กœ ์„ค์ • - writer.write("Content-Type: multipart/mixed; boundary=\"boundary\"\r\n"); // ์ด๋ฉ”์ผ ๋ณธ๋ฌธ ์œ ํ˜• ๋ฉ€ํ‹ฐํŒŒํŠธ(ํ…์ŠคํŠธ+์ฒจ๋ถ€ํŒŒ์ผ)์œผ๋กœ ์ง€์ • - writer.write("\r\n--boundary\r\n"); // ๋ณธ๋ฌธ๊ณผ ์ฒจ๋ถ€ ํŒŒ์ผ ๊ตฌ๋ถ„ - writer.write("Content-Type: text/plain; charset=UTF-8\r\n\r\n"); // ํ…์ŠคํŠธ ํ˜•์‹ ๋ช…์‹œ - writer.write(messageBody + "\r\n"); // ๋ณธ๋ฌธ ๋‚ด์šฉ ์ถ”๊ฐ€ +- **EmailServiceWithNaver.java** +
+ EmailServiceWithNaver.java + + ```javascript + package email.smtp; + + import email.mime.MimeMessageBuilder; + + import java.io.*; + import java.net.*; + import java.util.Base64; + import java.util.ArrayList; + import java.util.List; + import javax.net.ssl.*; + + public class EmailServiceWithNaver { + protected SSLSocketFactory factory; + protected SSLSocket socket; + protected PrintWriter out; + protected BufferedReader in; + protected String mail, password, smtpServer; + protected int port; + + // List to store requests and responses + protected List responses; + + public EmailServiceWithNaver(String mail, String password, String smtpServer, int port) { + this.mail = mail; + this.password = password; + this.smtpServer = smtpServer; + this.port = port; + this.responses = new ArrayList<>(); // Initialize response list + } + + // Check if a valid domain name has been entered + public boolean isCorrectAddress() { + return port != -1; + } + + public void connect() throws IOException { + System.out.println("Attempting to connect to SMTP server: " + smtpServer + " Port: " + port); + + factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); + socket = (SSLSocket) factory.createSocket(smtpServer, port); + in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream())); + + // Start handshake + System.out.println("Starting handshake..."); + socket.startHandshake(); // Start handshake + + // Process server response and send commands + getSingleResponse(); // Read server response + + // Send EHLO command + sendCommand("EHLO " + smtpServer); + get250Response(); + + // Send AUTH LOGIN command + sendCommand("AUTH LOGIN"); + getSingleResponse(); + + // Send encoded email address + sendCommand(Base64.getEncoder().encodeToString(mail.getBytes("UTF-8"))); + + String authResponses = getSingleResponse(); + + // Check responses during authentication process + + // Send encoded password + sendCommand(Base64.getEncoder().encodeToString(password.getBytes("UTF-8"))); + authResponses = getSingleResponse(); + + // Check responses during authentication process + if (!checkResponse(authResponses)) { + throw new IOException("Authentication failed: Please enter a valid email/password."); + } + // Check final response + } + + // Method to output requests and responses + protected void sendCommand(String command) throws IOException { + System.out.println("Client command: " + command); + out.println(command); + out.flush(); + } + + public void sendEmail(String to, String subject, String body,File[] attachments) throws IOException { + // Create and send message + MimeMessageBuilder builder = new MimeMessageBuilder(mail, to, subject, body, attachments); + String mimeMessage = builder.build(); + + sendCommand("MAIL FROM:<" + mail + ">"); + String response = getSingleResponse(); + + sendCommand("RCPT TO:<" + to + ">"); + response = getSingleResponse(); + if (!checkResponse(response)) { + throw new IOException("An error occurred with the recipient's email address. Please check if it is correct.\n" + String.join(", ", response)); + } + + sendCommand("DATA"); + response = getSingleResponse(); + if (!checkResponse(response)) { + throw new IOException("An error occurred during the data transmission preparation.\n " + String.join(", ", response)); + } + + // Write and send email body + + out.print(mimeMessage + "\r\n.\r\n"); + out.flush(); + response = getSingleResponse(); + + if (!checkResponse(response)) { + throw new IOException("An error occurred while sending the email body.\n " + String.join(", ", response)); + } + } + public void Quit() throws IOException { + // Send QUIT command + System.out.println("Sending QUIT command"); + out.println("QUIT"); + out.flush(); + String response = getSingleResponse(); + if (!checkResponse(response)) { + throw new IOException("An error occurred during the connection termination process.\n " + String.join(", ", response)); + } + // Close socket + socket.close(); + out.close(); + in.close(); + System.out.println("Email sent and connection terminated"); + } + + public void sendNoop() throws IOException { + // NOOP ๋ช…๋ น ๋ณด๋‚ด๊ธฐ + sendCommand("NOOP"); + + // ์„œ๋ฒ„ ์‘๋‹ต ์ฝ์Œ + String response = getSingleResponse(); + + // ์‘๋‹ต์„ฑ๊ณตํ–ˆ๋Š”์ง€ ํ™•์ธ (2xx or 3xx) + if (checkResponse(response)) { + System.out.println("NOOP ๋ช…๋ น ์„ฑ๊ณต, ์—ฐ๊ฒฐ ์œ ์ง€๋จ."); + } else { + throw new IOException("์—ฐ๊ฒฐ ์œ ์ง€์— ์‹คํŒจ ํ•จ. ์„œ๋ฒ„ ์‘๋‹ต: " + response); + } + } + + // Read server response + public String[] get250Response() throws IOException { + ArrayList responses = new ArrayList<>(); // ArrayList to store responses + String response; + + // Read multiple lines of responses + while ((response = getSingleResponse()) != null) { + responses.add(response); // Add response + if (!response.startsWith("250-")) { // Stop loop if not starting with 250 + break; + } + } + + return responses.toArray(new String[0]); // Convert ArrayList to array and return + } + + public String getSingleResponse() throws IOException { + String response = in.readLine(); // Read a single line + if (response != null) { + System.out.println(response); // Print the response + } + return response; // Return the response + } + + // Check an array of responses + + // Check a single response + public boolean checkResponse(String reply) throws NullPointerException { + return reply.startsWith("2") || reply.startsWith("3"); + } + + + // Email address validation + @Override + public String toString() { + return "Server: " + smtpServer + ", Mail ID: " + mail; + } + } + ``` +
+ + - ๋„ค์ด๋ฒ„ SMTP ์„œ๋ฒ„์™€ ์•ˆ์ „ํ•œ ์—ฐ๊ฒฐ์„ ๊ตฌ์ถ•ํ•˜๊ณ , ์ด๋ฉ”์ผ ์ธ์ฆ๊ณผ ๋ฐ์ดํ„ฐ ์ „์†ก์„ ์ˆ˜ํ–‰ + + - `isCorrectAddress` + - ํฌํŠธ๊ฐ€ `-1`์ด ์•„๋‹Œ ๊ฒฝ์šฐ ์œ ํšจํ•œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ๊ฐ„์ฃผ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์œ ํšจํ•˜์ง€ ์•Š์€ ์ฃผ์†Œ๋กœ ๊ฐ„์ฃผ + - `connect` + - SMTP ์„œ๋ฒ„์™€ SSL์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ ์„ค์ •, ๊ธฐ๋ณธ ์ธ์ฆ ์ˆ˜ํ–‰ + - EHLO ๋ช…๋ น โ†’ ์„œ๋ฒ„์™€ ํ†ต์‹  ์‹œ์ž‘ + - AUTH LOGIN ๋ช…๋ น โ†’ ์ธ์ฆ ๊ณผ์ • ์ง„ํ–‰ + - ์ด๋ฉ”์ผ ์ฃผ์†Œ์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ Base64๋กœ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ์ „์†ก + - `sendEmail` + - `MimeMessageBuilder` โ†’ MIME ํ˜•์‹์˜ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ + - `MAIL FROM` `RCPT TO` `DATA` โ†’ SMTP ์„œ๋ฒ„์— ์ด๋ฉ”์ผ ์ „์†ก + - MIME ๋ฉ”์‹œ์ง€๋ฅผ ์ƒ์„ฑ ํ›„, ์ฒจ๋ถ€ ํŒŒ์ผ์ด ์žˆ์„ ๊ฒฝ์šฐ ํ•จ๊ป˜ ์ „์†ก + - `Quit` + - SMTP ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์ข…๋ฃŒ + - ์†Œ์ผ“, ์ŠคํŠธ๋ฆผ ๋‹ซ์•„ ๋ชจ๋“  ์ž์› ํ•ด์ œ + - `sendNoop` + - `NOOP`โ†’ ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์œ ์ง€. ์„œ๋ฒ„ ์‘๋‹ต์ด ์„ฑ๊ณต ์ฝ”๋“œ(2xx, 3xx)๋กœ ์‹œ์ž‘ํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ˆ์™ธ + - `Response` + - `getSingleResponse()`: ํ•œ ์ค„์˜ ์„œ๋ฒ„ ์‘๋‹ต์„ ์ฝ๊ณ , ์ด๋ฅผ ์ถœ๋ ฅ ๋ฐ ๋ฐ˜ํ™˜ + - `get250Response()`: `250-`์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋‹ค์ค‘ ๋ผ์ธ ์‘๋‹ต ์ฒ˜๋ฆฌ, ๊ฐ ์‘๋‹ต์„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ + - `checkResponse`: ์‘๋‹ต ์ฝ”๋“œ๊ฐ€ 2xx ๋˜๋Š” 3xx๋กœ ์‹œ์ž‘ํ•˜๋ฉด ์„ฑ๊ณตํ•œ ์‘๋‹ต์œผ๋กœ ๊ฐ„์ฃผ + - `toString` + - SMTP ์„œ๋ฒ„์™€ ๋ฉ”์ผ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฌธ์ž์—ด์„ ์ œ๊ณต + +### 4. *flatlaf-3.5.2.jar* - // ์ฒจ๋ถ€ ํŒŒ์ผ ์ฒ˜๋ฆฌ - // FileHandler ์ž‘์„ฑํ•ด์ฃผ์‹  ํ•จ์ˆ˜ ์‚ฌ์šฉํ•ด์„œ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋  ๋“ฏํ•ฉ๋‹ˆ๋‹ค. - - // ์ด๋ฉ”์ผ ์ „์†ก ์ข…๋ฃŒ - writer.write("\r\n--boundary--\r\n.\r\n"); // ์ข…๋ฃŒ ํ‘œ์‹œ - writer.flush(); - readResponse(reader); - - // QUIT ๋ช…๋ น์œผ๋กœ ์—ฐ๊ฒฐ ์ข…๋ฃŒ - sendCommand(writer, "QUIT"); // ์ข…๋ฃŒ - System.out.println("์ด๋ฉ”์ผ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); - return true; // ์„ฑ๊ณตํ•˜๋ฉด true ๋ฐ˜ํ™˜ - - } catch (IOException e) { // ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ - e.printStackTrace(); - System.out.println("์ด๋ฉ”์ผ ์ „์†ก ์‹คํŒจ."); - return false; // ์‹คํŒจํ•˜๋ฉด false ๋ฐ˜ํ™˜ - } - } - - // SMTP ์„œ๋ฒ„์— ๋ช…๋ น์–ด ์ „์†ก ๋ฉ”์†Œ๋“œ - // writer ๋ช…์‹œ + ๋ช…๋ น์–ด(String) ํ˜•์‹์œผ๋กœ ์ž‘์„ฑ - private void sendCommand(BufferedWriter writer, String command) throws IOException { - writer.write(command + "\r\n"); // ๋ช…๋ น์–ด ์ „์†ก - writer.flush(); // ๋ฒ„ํผ ๋น„์›€ - } - - // SMTP ์„œ๋ฒ„์˜ ์‘๋‹ต์„ ์ฝ๊ณ  ์ถœ๋ ฅ - private String readResponse(BufferedReader reader) throws IOException { - String response = reader.readLine(); // ์‘๋‹ต ์ฝ์Œ - System.out.println("Server: " + response); // ์„œ๋ฒ„ ์‘๋‹ต ์ถœ๋ ฅ - return response; // ์‘๋‹ต ๋ฐ˜ํ™˜ - } -} - -``` -
- -- `Auth.java`: ์‚ฌ์šฉ์ž ์ธ์ฆ ๋ฐ SMTP ์„œ๋ฒ„ ์—ฐ๊ฒฐ ์ฒ˜๋ฆฌ -- `Client.java`: ์ด๋ฉ”์ผ ์ „์†ก ๋ฐ ํŒŒ์ผ ์ฒจ๋ถ€ ๊ด€๋ จ ๊ธฐ๋Šฅ + - `FlatLaf`: GUI ํ…Œ๋งˆ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์˜คํ”ˆ ์†Œ์Šค `Look and Feel library` + - ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋˜๋Š” `Look and Feel`์„ ๋Œ€์ฒดํ•˜์—ฌ ํ˜„๋Œ€์ ์ด๊ณ  ์„ธ๋ จ๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ + - Light, Dark, IntelliJ, Darcula ์˜ ํ…Œ๋งˆ ์ œ๊ณต + - ๋‹ค์–‘ํ•œ ์šด์˜ ์ฒด์ œ(Windows, macOS, Linux ๋“ฑ)์—์„œ ์ผ๊ด€๋œ UI๋ฅผ ์ œ๊ณต +