뒤로
오영준
오영준 ·

Django로 자동 이메일 구현하기

이번 메이커로그에서는 조금 기술적인 얘기를 해보려 합니다. 비개발자인 저에게는 꽤나 큰 챌린지이자 공부였거든요. First1000 클럽에 딱 맞는 그로스 얘기는 아니지만, 그로스를 위한 기술 작업이기 때문에 자동 이메일의 배경 설명과 함께 기록용으로 적어봅니다.

*개발자분들께: 혹시 제가 잘못 이해/묘사한 부분이 있다면 알려주세요! 수정해두겠습니다.

저는 개발자는 아니고, 지금까지 두 개의 스타트업에서 PM으로 3년 가까이 일한 경험만 있습니다. 다만 제 머릿속에 있는 걸 실제 움직이는 무언가로 구현해보는 걸 좋아해 취미로 개발을 배운지가 4년 정도 되었어요.

저는 장고(Django)라는 파이썬 기반 웹 프레임워크를 사용해 이것저것 많이 만들어봤지만, '자동 이메일 구현'은 한 번도 해본 적이 없는 기능이었습니다. 지금까지는 DB에서 데이터 가져다가 로직 짜고 API 만들어서 화면에 그려주는 것, 그러니까 아주 기본적인 것만 해왔는데, 휴튼의 그로스를 위해 자동 이메일 기능이 필요하다고 판단하여 새로운 기술적 시도를 해보았습니다.

📮 자동 이메일 기능? 왜?

사실 자동 이메일은 흔히 쓰이는 장치이기 때문에 별다른 설명은 필요하지 않을 것 같습니다. 그럼에도 휴튼에 대입하여 맥락을 소개드리면 이렇습니다.

먼저 저는 AARRR에서 앞 세 단계인 Acquisition, Activation, Retention에 집중하고 있습니다. 그 중에서도 Activation과 Retention이 가장 중요하다고 판단하고 있어요. (그 중에서도.........)

그래서 아래와 같이 각 퍼널별 액션 아이템을 펼쳐놓고 우선순위에 따라 제품/비제품 작업을 쳐내고 있습니다. 물론 제품의 성격에 따라 Activation과 Retention의 정의는 다르겠죠?

스크린샷 2023-07-15 오후 3.28.49.png

각 액션의 우선순위가 매겨지는 기준 중 하나는 '몇 개의 퍼널을 건드릴 수 있는가'입니다. 자동 이메일의 경우 Activation과 Retention 모두에 효과가 있는 액션입니다. 예를 들어 가입했을 때 환영 이메일, 내 글에 댓글이 달렸을 때 알림 이메일 등으로 활용할 수 있는 여지가 많으니까요. 특히 휴튼과 같이 아직 웹밖에 없는 제품은 자동 이메일이 더욱 중요하다고 생각했습니다.

제가 좋아하는 Fogg 모델을 가져와보면, 자동 이메일은 모델의 세 가지 요소 중 두 가지를 건드립니다.

  1. Trigger : 이 행동을 해야 한다는 신호의 역할을 함

  2. Motivation : 메일 내용을 효과적으로 구성하여 유저가 행동하고자 하는 동기를 높일 수 있음

다만 자동 이메일이 (비개발자인 저에게는) 기술적으로 한 번도 해보지 않은 거라 망설이고 있었는데요, 최근 유저 피드백 및 제품 전략을 고민하다가 우선순위를 높여 진행하기로 결정하였습니다.

🤫 백그라운드에서 작업 돌리기

자동 이메일을 보내는 절차는 사실 굉장히 간단합니다. 예를 들어 "가입한 뒤 3일 동안 들어오지 않은 유저에게" 메일을 보낸다고 해볼까요. 절차는 이렇습니다.

  1. 매일 특정 시간에, 가입한 날짜가 오늘로부터 3일이 초과하는 유저를 DB에서 골라냅니다.

  2. 이 유저들의 정보를 API에 담아 메일링 툴(저는 스티비를 사용합니다)로 쏴줍니다.

  3. 그럼 메일링 툴이 알아서 해당 유저들에게 메일을 발송합니다.

문제는, "매일 특정 시간에" 특정 업무(유저 골라내기)를 수행해야 한다는 것입니다. 물론 제가 수작업으로 매일 직접 DB에서 조건에 맞는 데이터를 뽑아내도 되지만, 발송해야 하는 메일의 종류가 다양해지면 지나치게 비효율적인 일이 될 것 같았어요. 그렇기 때문에 제가 직접 수행하지 않아도 뒤에서 제 일을 대신 해줄 놈이 필요했습니다.

한편 제가 장고를 사랑하는 이유는 쉽게 갖다 쓸 수 있는 패키지가 풍부하기 때문입니다. 그래서 누가 저에게 "너 이런 건 어떻게 구현한 거야?"라고 물어보면 "몰라 그냥 장고에서 갖다 쓰니까 되던데?"라고 답하는 경우가 부지기수였습니다. (좋은 건 아닌 것 같습니다 😏)

그래서 이러한 백그라운드 작업도 당연히 장고 패키지가 있을 거라고 생각했습니다. ChatGPT에게 물어보니 역시, django-background-tasks라는 게 있다네요. 오케이, 이번에도 원리 따위는 모르는 채로 구현할 수 있겠군. 그래서 ChatGPT가 친절하게 알려준대로 진행을 했습니다.

그런데, 계속해서 똑같은 오류가 발생합니다. ChatGPT가 뻔뻔한 거짓말을 자주 뱉는 녀석이긴 하지만, 이 오류는 이렇게 해봐도 저렇게 해봐도 도저히 해결되지 않았습니다. 그래서 구글링을 해봤더니 이럴수가, django-background-tasks는 더 이상 장고에서 지원하지 않는다는 겁니다.

간단히 해결할 수 있을 거라는 기대감을 잠시 접어둔 채 열심히 구글링을 해봤습니다. 그러다가 찾은 것이 Celery와 Redis라는 놈들입니다.

🥦 Celery..? Redis..?

낯선 기술을 도입하는 건 저와 같이 기술에 대한 깊은 이해 없이 피상적인 수준으로만 개발을 하는 사람에게는 특히 두려운 일인데요, 여러 아티클을 읽으며 공부해보니 Celery와 Redis라는 조합을 사용하여 (두려워했던 것보다는) 쉽게 구현할 수 있었습니다.

먼저 Celery는 현재 서버에서 주고받는 요청과 독립적으로 움직이는 놈입니다. 이걸 기술적인 용어로 '비동기'라고 한다네요. 그러니까 누군가가 직접 실행하지 않아도, 서버에서 다른 작업이 돌아가고 있어도 Celery는 비동기로 묵묵히 자기 할 일을 하는 놈입니다.

Redis는 임시 서버 정도로 이해하실 수 있습니다. 이 과정에서는 "Message broker"라는 역할을 하는데요, 해야 할 일을 장고로부터 받아, 작업을 수행할 Celery에게 전달하는 역할을 합니다. 실제로는 퍼포먼스 개선을 위한 캐싱 용도로도 많이 사용한다고 해요.

Celery는 또 두 가지로 나뉩니다.

  1. Worker : Redis로부터 일을 받아 실제로 수행하는 녀석입니다.

  2. Beat : 주기적으로 작업을 할당하는 녀석입니다. 예를 들어 "매일 특정 시간에" 해야 하는 일이라면 Celery beat가 그 주기에 맞게 Redis에 작업을 넣어두는 것이죠. 그럼 그걸 worker가 가져다가 수행합니다. 주기적으로 수행할 작업이 없다면 이 놈은 필요 없습니다.

정리

정리하면 이렇습니다. 먼저 설정해둔 주기(하루, 1시간, 1분, ...)에 맞춰 Celery beat가 Redis라는 임시 저장소에 할 일을 할당합니다. 예를 들어 "유저 A에게 메일 보내기"가 있겠죠. 그럼 Celery worker가 그 작업을 확인하고 가져가다가 수행합니다. 그러니까 메일링 툴(스티비)에게 API를 쏘는 역할을 합니다.

생각보다 간단하지 않나요?

스크린샷 2023-07-15 오후 3.53.44.png

이미지 출처 👇

제가 그로스를 위해 자동 이메일을 어떻게 활용했는지는 다른 메이커로그에서 소개드리겠습니다. 🙂

*미흡하거나 잘못된 설명이 있었다면 꼭꼭 알려주세요!

First1000 그룹의 글
4

댓글

로그인 후 댓글을 남길 수 있습니다.

Doeon Kwon 권도언
Doeon Kwon 권도언

영준님 메이커로그가 Must Reads #225에 선정되었습니다 :) https://stib.ee/fIS8