λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

ν”„λ‘œμ νŠΈ/Airbnb Clone

[νŠΈλŸ¬λΈ” μŠˆνŒ…] jakarta.mail.internet.addressexception: local address contains control or whitespace

ꡬ글링 해도 λ‚˜μ˜€μ§€ μ•Šλ˜ μ—λŸ¬λ₯Ό ν•΄κ²°ν•˜λŠ” 과정을 μ†Œκ°œν•˜λ©°, μ™œ λ°œμƒν•˜κ³  μ–΄λ–»κ²Œ ν•΄κ²°ν–ˆλŠ”μ§€ μ†Œκ°œν•˜λŠ” κΈ€μž…λ‹ˆλ‹€.
SMTP κΈ°λŠ₯에 λŒ€ν•΄ μ„€λͺ…ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ„œλ‘ 

에어비앀비에 νšŒμ›κ°€μž…ν•  λ•Œ, νšŒμ›μ΄ μž…λ ₯ν•œ 이메일이 정상 이메일인지 ν™•μΈν•˜κ³ μž 인증번호λ₯Ό λ³΄λ‚΄κ³ μž ν–ˆμŠ΅λ‹ˆλ‹€.

κ·Έλž˜μ„œ, μ•„λž˜μ™€ 같은 μ½”λ“œλ‘œ 넀이버 μ„œλ²„μ— 메일을 λ³΄λƒˆμœΌλ‚˜, `jakarta.mail.internet.addressexception: local address contains control or whitespace` μ—λŸ¬κ°€ javaMailSender.send(message) μ—μ„œ λ°œμƒν•˜μ˜€μŠ΅λ‹ˆλ‹€.

public void sendVerificationEmail(String memberEmail) {
        try {
            SimpleMailMessage message = new SimpleMailMessage();

            message.setFrom(env.getProperty("spring.mail.username"));
            message.setTo(memberEmail);
            message.setSubject("Airdnb 클둠 ν”„λ‘œμ νŠΈμ—μ„œ 보낸 인증번호 μž…λ‹ˆλ‹€");
            message.setText(createRandomUUID());

     >>>>   javaMailSender.send(message);  <<<< μ—λŸ¬ λ°œμƒ μœ„μΉ˜
        } catch (MailException e) {
        }
    }

 

ν•΄κ²°κ³Όμ • μ†Œκ°œ

1.μ—λŸ¬λ₯Ό μ§μ—­ν•˜κ³ , ꡬ글링을 톡해 ν’€κ³ μž ν–ˆμŠ΅λ‹ˆλ‹€.

 

μ—λŸ¬λ₯Ό μ§μ—­ν•˜μžλ©΄, λ‚΄ 둜컬 λ„€νŠΈμ›Œν¬ μ£Όμ†Œμ— control μ΄λ‚˜ 곡백이 ν¬ν•¨λ˜μ–΄ μžˆλ‹€λŠ”λ° 와닿지 μ•Šμ•„μ„œ  ꡬ글링을 ν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€. ꡬ글링을 ν–ˆμœΌλ‚˜ μ™œ 이런 였λ₯˜κ°€ λ°œμƒν–ˆκ³ , μ–΄λ–»κ²Œ ν•΄κ²°ν–ˆλŠ”μ§€ λ‚˜μ™€μžˆλŠ” 글을 찾지 λͺ»ν•΄μ„œ StackTrace λ₯Ό 거슬러 μ˜¬λΌκ°€κ³ μž ν–ˆμŠ΅λ‹ˆλ‹€.

 

2. StackTrace λ₯Ό 타고 μ‹¬μ—°μœΌλ‘œ λ“€μ–΄κ°€κΈ°


StackTrace 쀑, InternetAddress.java:1352 에 보면, String 을 for 문으둜 λŒλ©΄μ„œ char c κ°€ ν•΄λ‹Ή if문에 참일 경우 ν•΄λ‹Ή μ˜ˆμ™Έκ°€ λ°œμƒν•˜λŠ” 것을 ν™•μΈν•˜μ˜€μŠ΅λ‹ˆλ‹€.

- InternetAddress.java:1352

if (c <= 040 || c == 0177)
    throw new AddressException(
        "Local address contains control or whitespace", addr);

 

if 문의 의미λ₯Ό ν•΄μ„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. λ¨Όμ €, 040 와 0177 의 숫자 ν‘œκΈ°λ²•μ€ 8μ§„λ²•μ΄λ‹ˆ 10μ§„λ²•μœΌλ‘œ λ°”κΎΈκ² μŠ΅λ‹ˆλ‹€.

8진법 '040'은 10진법 '32'둜 μΉ˜ν™˜λ˜λ©°, 8진법 '0177'은 10진법 '127'둜 μΉ˜ν™˜λ©λ‹ˆλ‹€. 그리고, 10진법은 ASCII λ¬Έμžμ™€ λŒ€μ‘λ©λ‹ˆλ‹€.


즉, char c κ°€ ASCII 문자둜 32 보닀 μž‘κ±°λ‚˜ 127 κ³Ό κ°™λ‹€λ©΄ μ—λŸ¬κ°€ λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.
ASCII 문자 μ—μ„œ 32보닀 μž‘κ³ , 127인 문자λ₯Ό 곡백문자 및 μ œμ–΄λ¬ΈμžλΌ ν•©λ‹ˆλ‹€.

κ·Έλ ‡λ‹€λ©΄, μ–΄λ–€ String μ—μ„œ κ³΅λ°±λ¬Έμžμ™€ μ œμ–΄λ¬Έμžκ°€ μžˆλŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ String 을 μ–΄λ””μ„œ λ°›λŠ”μ§€ StackTrace λ₯Ό λ‹€μ‹œ μΆ”μ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

 

κ·Έ 결과둜 JavaMailSenderImpl.java:314 μ—μ„œ String 은 SimpleMailMessage μ—μ„œ λ‚˜μ˜€λŠ” 것을 ν™•μΈν•˜μ˜€μŠ΅λ‹€.

- JavaMailSenderImpl.java:314

@Override
    public void send(SimpleMailMessage... simpleMessages) throws MailException {
        List<MimeMessage> mimeMessages = new ArrayList<>(simpleMessages.length);
        for (SimpleMailMessage simpleMessage : simpleMessages) {
            MimeMailMessage message = new MimeMailMessage(createMimeMessage());
>>> 314라인 simpleMessage.copyTo(message);  <<<
            mimeMessages.add(message.getMimeMessage());
        }
        doSend(mimeMessages.toArray(new MimeMessage[0]), simpleMessages);
    }

 

λ””λ²„κΉ…μœΌλ‘œ SimpleMailMessage 에 μ–΄λ–€ 값듀이 λ“€μ–΄κ°€λŠ”λ₯Ό ν™•μΈν•˜μ˜€κ³ , ν΄λΌμ΄μ–ΈνŠΈκ°€ μš”μ²­ν•˜λŠ” 데이터에 곡백 문자인 '\r\n' κ°€ μžˆλŠ” 것을 ν™•μΈν•˜μ˜€μŠ΅λ‹ˆλ‹€.

 

즉, μ»¨νŠΈλ‘€λŸ¬μ—μ„œ 받은 μš”μ²­ JSON이 νŒŒμ‹±λ˜μ§€ μ•Šκ³ , 문자 κ·ΈλŒ€λ‘œμΈ String 으둜 Service κΉŒμ§€ λ„˜μ–΄κ°„ 것이 μ›μΈμ΄μ—ˆκ³ , μ»¨νŠΈλ‘€λŸ¬μ—μ„œλŠ” { "email": "gromit1234@naver.com" } 인 JSON을 @RequestBody String email 으둜 λ°›κ³ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

λ‹¨μˆœν•˜κ²Œ @RequestBody μ‚¬μš©ν•˜λ©΄, JSON이 νŒŒμ‹±λ˜μ–΄ μ›ν•˜λŠ” κ°’λ§Œ λ‚˜μ˜¬ 것이라 μƒκ°ν•˜λ˜ μ§€μ‹μ˜ 였λ₯˜κ°€ μ›μΈμ΄μ—ˆμŠ΅λ‹ˆλ‹€...

 

이 μ§€μ‹μ˜ 였λ₯˜λ₯Ό κΉ€μ˜ν•œλ‹˜μ˜ μŠ€ν”„λ§ λ©”μ‹œμ§€ 컨버터 κ°•μ˜λ‘œ λ°”λ‘œ μž‘μ•˜μŠ΅λ‹ˆλ‹€πŸ˜‚
@ResponseBody λž‘ @RequestBody κ°€ μžˆμ„ μ‹œ, μŠ€ν”„λ§ λΆ€νŠΈλŠ” 클래슀 νƒ€μž…κ³Ό λ―Έλ””μ–΄ νƒ€μž…(ν—€λ”μ˜ Content-Type || Accept)을 boolean λ°©μ‹μœΌλ‘œ μ²΄ν¬ν•΄μ„œ μ–΄λ–€ λ©”μ‹œμ§€ 컨버터λ₯Ό μ‚¬μš©ν•  것인지 κ²°μ •ν•œλ‹€κ³  ν•©λ‹ˆλ‹€.

0 = ByteArrayHttpMessageConvertor (λ°”μ΄νŠΈ 처리)
1 = StringHttpMessageConvertor (문자 처리)
2 = MappingJackson2HttpMessageConvertor (객체/JSON 처리)
3= Jaxb2RootElementHttpMessageConverter (XML 처리)
...(μ€‘λž΅)

 

문자λ₯Ό μ²˜λ¦¬ν•˜λŠ” StringHttpMessageConvertor 의 클래슀 νƒ€μž…μ€ String , λ―Έλ””μ–΄ νƒ€μž…μ€ */* 이기 λ•Œλ¬Έμ— @RequestBody String email 의 경우, MappingJackson2HttpMessageConvertor λŒ€μ‹ μ— StringHttpMessageConvertor κ°€ μ„ νƒλ˜μ–΄ JSON 이 νŒŒμ‹±λ˜μ§€ μ•ŠλŠ” κ²ƒμ΄μ—ˆμŠ΅λ‹ˆλ‹€.

 

κ·Έλž˜μ„œ EmailVertificationDto 클래슀λ₯Ό λ§Œλ“€κ³ , @RequestBody 의 ν΄λž˜μŠ€νƒ€μž…μ„ Object 둜 λ§Œλ“€μ–΄μ€ŒμœΌλ‘œμ¨ μ§€μ‹μ˜ 였λ₯˜λ₯Ό 작고 ν•΄κ²°ν•˜κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

 

마치며

μ½”λ“œμŠ€μΏΌλ“œλ₯Ό λ‹€λ‹ˆλ©° Learning By Doing λ°©μ‹μœΌλ‘œ ν•™μŠ΅ν•œ 것듀이 기얡에 였래 남고, 이해가 훨신 μž˜λ˜λŠ” 것을 λͺΈμ†Œ μ²΄ν—˜ν•΄μ™”μ—ˆλŠ”λ°, 이번 일을 κ³„κΈ°λ‘œ ν™•μ‹€νžˆ 인강을 κ·Έλƒ₯ λ“£λŠ” 것은 λ‚΄κ²ŒλŠ” λ§žμ§€ μ•ŠλŠ” λ°©μ‹μž„μ„ 확인 ν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

 

이둜 인해, μ•žμœΌλ‘œλ„ 무엇을 λ§Œλ“€μ–΄κ°€λ©° ν•„μš”ν•œ 곡뢀λ₯Ό 진행할 κ³„νšμ΄λ©° Learning By Doing 둜 ν•™μŠ΅ν•΄ λ‚˜κ°ˆ κ²ƒμž…λ‹ˆλ‹€.

μ½”λ“œμŠ€μΏΌλ“œ λ§Œλ§Œμ„ΈπŸ™Œ(?)