Feign과 Mailgun 조합으로 이메일 인증 기능 구현하기

jina·2024년 9월 25일

Spring

목록 보기
7/8

Feign 소개

Feign은 원래 넷플릭스(Netflix)에서 개발한 HTTP 클라이언트 바인더입니다. Spring Cloud는 이 Feign이라는 도구를 통합해서 Spring과 함께 사용할 수 있도록 지원하는 기능을 제공합니다. 클라우드에서 제공하는 Spring Cloud OpenFeign이라는 형태의 도구를 사용하면, Spring Boot와 자연스럽게 연동하여 REST API 호출을 간편하게 처리할 수 있습니다.

Feign 기능

  • HTTP 클라이언트 바인더: API 호출을 추상화하는 기능을 제공하는 도구
  • 간편한 호출: HTTP 요청을 보내는 데 필요한 코드 작성을 간소화

Spring Cloud OpenFeign 기능

  • 의존성 주입: Spring Bean과의 의존성 주입을 통해 클라이언트 간에 쉽게 연결할 수 있습니다.
  • 어노테이션 기반 설정: @FeignClient 어노테이션으로 간단하게 외부 API 클라이언트를 정의할 수 있습니다.
  • 환경 설정과 유연성: Feign은 application.yml 또는 application.properties 파일에서 쉽게 환경 설정을 조정할 수 있습니다.

Feign 셋업 방법

1. 프로젝트에 Feign 의존성 추가

build.gradle 파일에 Feign 의존성을 추가합니다.

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
}

2. @EnableFeignClients 어노테이션 설정

@EnableFeignClients를 사용해 Feign을 활성화합니다. Spring Boot 애플리케이션의 메인 클래스에 추가합니다.

@SpringBootApplication
@EnableFeignClients
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }
}

3. 이메일 전송을 위한 Feign Client 만들기

이메일 전송을 처리하는 외부 API로 Mailgun을 이용해 보겠습니다.

Mailgun Open API란?
이메일 전송, 수신, 추적 기능을 제공하는 이메일 API 서비스입니다. 특히 대량 이메일 발송과 인증 메일 전송에 적합합니다. 복잡한 SMTP 설정 없이 REST API로 쉽게 전송 기능을 사용할 수 있습니다. 하루에 메일 전송이 100개 이하라면 무료 플랜으로 사용이 가능합니다.

Mailgun에서는 사용자에게 제공한 API키와 특정 도메인을 조합해서 이메일을 전송할 수 있는 엔드포인트를 제공합니다. 이를 Feign Client로 호출할 수 있게 설정합니다.

3-1. Mailgun API 키 설정

Mailgun API 키는 보안 상 민감한 정보이므로, Spring Boot의 application.yml 또는 환경 변수에 설정하는 것이 좋습니다.

# properties 파일 
mailgun.key=YOUR_MAILGUN_API_KEY   # Mailgun에서 받은 API key 값
mailgun.domain=YOUR_DOMAIN_ADDRESS  # 호출할 domain 주소 (예: sandboxXXXXXX.mailgun.org)

3-2. FeignClient 설정

FeignClient에서는 어떤 API를 호출할지 설정합니다. Feign을 통해 특정 API와 통신할 수 있는 인터페이스입니다. 아래 예시는 Mailgun 외부 API를 호출하는 코드입니다.

@FeignClient(name = "mailgun", url = "https://api.mailgun.net/v3")
public interface MailgunClient {

    @PostMapping("/{domain}/messages")
    void sendEmail(
        @RequestHeader("Authorization") String authorization,
        @PathVariable("domain") String domain,
        @RequestBody SendMailForm emailRequest);  // DTO를 사용해 Body 작성
}

3-3. FeignConfig

FeignConfig에서는 특정 API를 호출할 때 어떻게 동작할지를 설정합니다. FeignClient가 작동할 때 필요한 설정을 정의하는 클래스입니다.

예시 코드에는 아래 설정 내용을 포함합니다.

  • 요청시 인증키 전달: Mailgun API 요청마다 인증 정보를 자동으로 추가합니다. api는 Mailgun에서 사용하는 기본 사용자명이고, mailgunKey는 Mailgun의 API 키입니다.
  • 타임아웃 설정: Feign Client가 서버로부터 응답을 받을 때 일정 시간(연결 5초, 읽기 10초)이 지나면 자동으로 타임아웃 에러를 발생시킵니다.
  • 예외 처리: API 호출 실패 시 404(Not Found)나 500(Internet Server Error)와 같은 상태 코드에 따라 맞춤형 예외를 처리할 수 있습니다.
  • 리트라이 설정: 요청이 실패하면 100ms 대기 후 다시 시도하며, 최대 3번까지 재시도합니다.
@Configuration
public class FeignConfig {

    // Mailgun API 키를 불러오기 위한 @Value 어노테이션
    @Value("${mailgun.key}")
    private String mailgunKey;

    // Feign 클라이언트에 Mailgun 인증 정보를 추가하는 인터셉터
    @Bean
    @Qualifier("mailgun")
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { 
        return new BasicAuthRequestInterceptor("api", mailgunKey); // Mailgun은 기본적으로 api 키로 인증
    }

    // Feign 클라이언트의 타임아웃 설정 (연결 타임아웃: 5초, 읽기 타임아웃: 10초)
    @Bean
    public Feign.Builder feignBuilder() {
        return Feign.builder()
                    .options(new Request.Options(5000, 10000)); // 연결 타임아웃 5초, 읽기 타임아웃 10초
    }

    // 예외 처리를 위한 커스텀 ErrorDecoder
    @Bean
    public ErrorDecoder errorDecoder() {
        return new CustomErrorDecoder(); // API 실패에 대한 맞춤형 예외 처리
    }

    // 리트라이 정책 설정 (100ms 대기 후 최대 3번까지 재시도)
    @Bean
    public Retryer retryer() {
        return new Retryer.Default(100, 1000, 3); // 리트라이: 최대 3번 시도, 100ms부터 시작
    }
}

// 커스텀 예외 처리를 위한 ErrorDecoder 구현
public class CustomErrorDecoder implements ErrorDecoder {

    @Override
    public Exception decode(String methodKey, Response response) {
        if (response.status() == 404) {
            return new NotFoundException("리소스를 찾을 수 없습니다.");
        } else if (response.status() >= 500) {
            return new ServerErrorException("서버에 오류가 발생했습니다.");
        }
        return new Exception("알 수 없는 오류가 발생했습니다.");
    }
}

4. 이메일 발송에 사용할 DTO 만들기

발송 서비스 메소드에서 메일 데이터를 작성할 때 사용할 DTO를 만듭니다.

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Builder
public class SendMailForm {

    private String from;
    private String to;
    private String subject;
    private String text;
}

5. 이메일 발송 서비스 만들기

이제 실제 발송을 위한 서비스 메소드를 작성합니다.

@Service
@RequiredArgsConstructor
public class EmailService {

    private final MailgunClient mailgunClient;

    @Value("${mailgun.domain}")
    private String domain;  // application.properties에서 가져온 도메인

    public void sendVerificationEmail(String email, String name, UserType type, String code) {
        // 이메일 본문 생성
        String emailBody = getVerificationEmailBody(email, name, type, code);

        // DTO 사용해서 이메일 데이터 작성
        SendMailForm emailForm = SendMailForm.builder()
            .from("no-reply@yourdomain.com")
            .to(email)
            .subject("이메일 인증을 완료해 주세요")
            .text(emailBody)  // 생성한 이메일 본문을 삽입
            .build();

        // Mailgun API 호출하여 이메일 전송 (Authorization은 FeignConfig에서 자동으로 처리)
        mailgunClient.sendEmail(domain, emailForm);
    }

    // 이메일 본문 생성 메소드 (서버 도메인 작성)
    private String getVerificationEmailBody(String email, String name, UserType type, String code) {
        return "안녕하세요, " + name + "님! 아래 링크를 클릭해서 인증을 완료해 주세요. \n\n" +
               "http://localhost:8080/signUp/" + type + "/verify?email=" + email + "&code=" + code;
    }
}

참고 공식 문서
Mailgun API Authentication
Mailgun Where can I find my API keys and SMTP credentials?

profile
오늘의 기록은 내일의 보물

0개의 댓글