업종코드 필터에서 무엇이 문제였나?
업종코드로 소프트웨어 개발사를 거르는 필터는 라벨 하나가 실체와 어긋나는 순간 조용히 뚫립니다. 2026년 8월 13일, 우리 영업 메일 발송 대기열에 응용 소프트웨어 개발사 한 곳이 올라 있었습니다. 이 회사의 업종코드는 “컴퓨터 및 주변장치, 소프트웨어 도매업”(G4651)이었고, 개발사를 걸러 내는 낱말 목록에는 “도매업”이 없었습니다.
저희가 파는 서비스는 홈페이지 제작과 업무 자동화 개발입니다. 직원 54명을 두고 응용 소프트웨어를 만드는 회사에 개발을 맡기라는 메일을 보내면, 받는 쪽은 발신자가 자기 회사를 전혀 보지 않았다고 판단합니다. 메일 한 통의 실수로 끝나지 않고, 같은 필터를 거친 대기열 전체를 의심하게 만드는 신호이기도 했습니다.
이 회사를 찾은 쪽은 코드가 아니라 사람이었습니다. 이미 메일을 클릭한 회사에 다시 연락하려고 대기열을 만들던 중, 대표가 목록을 눈으로 훑다가 회사 이름을 보고 멈췄습니다. 필터는 아무 경고도 내지 않았습니다. 업종코드 필터가 틀릴 때는 오류 메시지가 아니라 잘못 나간 메일로만 드러난다는 점이 이 문제의 핵심이었습니다.

이 글은 처음 잰 숫자, 세운 가설, 가설이 틀린 자리, 진짜 원인, 조치, 재측정, 남는 한계 순서로 적습니다. 같은 날 하루 발송 상한을 올린 판정은 콜드메일 발송량 상한 기록에 따로 적었고, 여기서는 필터 쪽만 깊게 봅니다. 처음부터 답을 알고 고친 일이 아니어서, 구현까지 하고 버린 보강안도 숫자와 함께 남깁니다.
처음 잰 숫자: 같은 업종코드 12곳, 클릭한 회사 34곳 중 11곳 차단
측정은 두 갈래로 했습니다. 하나는 발송 대기열을 업종코드별로 다시 세는 일이고, 다른 하나는 메일 클릭 기록을 발송 제외 목록과 맞대어 보는 일입니다. 두 숫자 모두 필터가 의도와 다르게 움직이는지를 보려는 측정이었습니다. 개발사 한 곳이 새어 나왔다면 같은 길로 나온 회사가 더 있는지, 반대로 막지 말아야 할 회사를 막고 있지는 않은지를 함께 봐야 했습니다.
- 발송 대기열 안에서 업종코드 G4651(컴퓨터 및 주변장치, 소프트웨어 도매업)인 회사는 12곳이었다
- 문제의 회사는 직원 54명을 둔 응용 소프트웨어 개발사였다
- 그때까지 메일 링크를 클릭한 회사는 34곳이었고, 그중 11곳이 발송 제외 목록에 막혀 재접촉 대상에서 빠져 있었다
- 막힌 11곳은 전부 8월 7일 하루에 클릭했다
두 번째 숫자는 반대 방향의 오류입니다. 8월 7일에는 규모 필터가 아직 없어서 대기업 묶음이 한 번 발송됐고, 11곳은 그 메일에 실제로 반응한 회사들이었습니다. 이후 대기업을 막으려고 발송 제외 목록에 이 회사들을 올렸고, 그 목록이 클릭한 회사의 재접촉까지 막고 있었습니다. 한쪽에서는 걸러야 할 회사가 새고, 다른 쪽에서는 반응한 회사가 막혀 있었습니다.
같은 날 발송 체계 전체의 숫자도 함께 봤습니다. 최근 30일 반송률은 4.3%였고 스팸 신고는 0건, 누적 발송은 832통이었습니다. 메일 링크 클릭은 61건까지 쌓였지만 문의는 0건이었습니다. 필터를 고치는 일이 문의 0건을 풀어 주리라고 기대하지는 않았지만, 대상이 틀린 채로 발송량을 늘리면 틀린 메일만 늘어난다는 점은 분명했습니다.
처음 세운 가설은 무엇이었나?
기존 설계는 “업종코드 이름에 개발을 뜻하는 낱말이 들어 있으면 개발사다”라는 가정 위에 서 있었습니다. 코드에는 이 낱말 목록이 DEV_KSIC_TOKENS라는 이름으로 들어 있고, 업종코드 이름에 목록의 낱말이 하나라도 있으면 그 회사를 발송 대상에서 뺍니다. 규칙이 단순하고 결과가 늘 같아서 테스트로 고정하기 쉬웠습니다.
구멍을 발견한 뒤 떠올린 가설은 세 가지였습니다. 가장 빠른 길은 문제의 회사 한 곳만 발송 제외 목록에 올리는 안이었습니다. 그다음은 낱말 목록에 “소프트웨어 도매업”을 추가하는 안이었고, 가장 큰 안은 업종코드 라벨 대신 사업자등록의 업태·종목 문구에서 개발 행위를 읽어 내는 두 번째 층을 붙이는 안이었습니다.
- 가설 1: 이 회사 한 곳이 예외다. 발송 제외 목록에 한 줄 넣으면 끝난다
- 가설 2: 낱말 목록이 “도매업” 형태를 몰랐다. “소프트웨어 도매업”을 추가하면 같은 유형이 전부 막힌다
- 가설 3: 업종코드 라벨 자체를 믿을 수 없다. 업태·종목 문구에서 개발 행위를 읽는 층을 하나 더 둬야 한다
세 번째 가설에는 그럴듯한 근거가 있었습니다. 업종코드는 회사가 등록할 때 고른 분류 하나지만, 업태·종목 문구는 회사가 하는 일을 여러 줄로 적은 텍스트라 정보가 더 많아 보였습니다. 기업 데이터베이스 21,961곳 가운데 이 문구가 채워진 회사가 18,325곳(83%)이라 범위도 충분해 보였습니다. 라벨이 틀린 회사를 텍스트로 잡아내면 이번 같은 사례를 미리 막을 수 있으리라고 기대했습니다.
세 가설은 같은 질문에 다르게 답합니다. 개발사 여부를 무엇으로 판정할 것인가. 가설 1은 사람이 찾은 개별 사례로, 가설 2는 업종코드 라벨로, 가설 3은 회사가 직접 적은 문구로 판정합니다. 아래에서 1과 3이 어디서 무너졌는지부터 적습니다.
가설은 어디서 틀렸나?
가설 1은 대기열 숫자 하나로 무너졌습니다. 같은 업종코드 G4651로 등록한 회사가 대기열에 12곳 있었으니, 한 곳만 빼면 나머지는 같은 길로 계속 나갑니다. 대표가 우연히 본 한 곳은 필터의 구멍이 드러난 지점일 뿐, 구멍의 크기가 아니었습니다. 개별 제외는 증상을 지우고 원인은 그대로 남기는 안이라 버렸습니다.
가설 3은 실제로 구현해서 돌려 본 다음에 버렸습니다. 업태·종목 문구에 “개발”과 소프트웨어성 낱말이 함께 나오면 개발사로 보는 조건을 만들어, 발송 후보 4,249곳에 적용했습니다. 이 조건 하나로 108곳(2.5%)이 추가로 빠졌습니다. 숫자만 보면 숨어 있던 개발사를 꽤 찾아낸 듯했습니다.
목록을 열어 보니 그림이 달랐습니다. 빠진 108곳에는 문구용 종이제품 제조사, 골판지 제조사, 부동산 임대사가 들어 있었습니다. 소프트웨어를 만드는 조직이 없는 회사들이 업태·종목에 “소프트웨어 개발, 공급” 같은 줄을 달고 있었고, 새 필터는 그 줄을 보고 이 회사들을 개발사로 판정했습니다. 정작 이 회사들은 업무 자동화를 사 갈 가능성이 큰 중소 제조사였습니다.
여기서 배운 점은 측정 단위였습니다. “추가로 몇 곳이 빠지는가”만 보면 108곳은 필터가 일을 많이 했다는 증거처럼 읽힙니다. 빠진 회사가 실제 개발사인지는 숫자가 아니라 회사 이름과 업종을 하나씩 봐야 알 수 있었습니다. 그 확인을 건너뛰었다면 저희는 고객이 될 수 있는 제조사 108곳을 지우고 필터를 개선했다고 기록했을 겁니다.

조건을 더 느슨하게 잡는 안은 결과가 더 나빴습니다. “개발” 한 낱말만 보면 제조업의 “신제품 개발” 같은 문구가 전부 걸립니다. 반대로 더 엄격한 근거를 찾으려고 국민연금 업종코드를 교차해 보는 안도 검토했지만, 저희가 가진 기업 데이터에는 그 값이 없었습니다. 따로 모으려면 수집 비용이 드는데, 그 비용을 정당화할 효과는 확인한 적이 없었습니다.
이 층을 켜면 정확히 우리가 노리는 중소 제조사를 잃는다.
진짜 원인은 무엇이었나?
원인은 데이터의 성격에 있었습니다. 한국 사업자등록의 업태·종목은 회사가 실제로 하는 일을 적는 칸이라기보다, 등록할 수 있는 항목을 나열하는 칸에 가깝습니다. 실제 개발 조직이 없어도 “소프트웨어 개발, 공급” 같은 항목을 흔히 붙여 둡니다. 텍스트가 많다고 정보가 많은 것이 아니었고, 이 칸의 글자는 실체가 아니라 가능성을 말했습니다.
업종코드 라벨도 실체를 완벽히 말하지는 않습니다. 문제의 회사는 개발을 하면서 도매업 코드로 등록했으니까요. 다만 두 데이터는 틀리는 방식이 다릅니다. 업종코드는 회사당 하나라서, 틀려도 그 코드 단위로 묶여서 틀립니다. 그래서 G4651처럼 코드 하나를 찾아내면 같은 유형 전체를 한 번에 고칠 수 있습니다. 업태·종목 문구는 회사마다 제각각 틀려서, 규칙으로 고칠 단위가 생기지 않습니다.
8월 7일 대기업 발송도 같은 구조에서 나왔습니다. 그날은 규모 필터가 아예 없어서 대기업 묶음이 그대로 나갔고, 그 뒤 붙인 발송 제외 목록은 “레퍼런스 없이 대기업에 먼저 들이밀지 않는다”는 목적으로 만든 장치였습니다. 그런데 메일을 받은 11곳이 먼저 클릭해 관심을 보인 순간, 그 목적은 사라졌습니다. 필터를 만든 이유와 필터가 막는 대상이 어긋나 있었습니다.
두 문제를 묶으면 원인은 하나로 모입니다. 필터는 만들 때의 이유를 기억하지 못하고, 걸러 낸 결과를 스스로 확인하지도 않습니다. 업종코드 필터는 낱말 목록이 모르는 코드를 통과시켰고, 발송 제외 목록은 상황이 바뀐 회사까지 계속 막았습니다. 둘 다 사람이 결과 목록을 열어 봐야만 보이는 오류였습니다.
조치: 낱말 한 줄 보강, 문구 층은 되돌림
업종코드 필터는 가설 2대로 고쳤습니다. 낱말 목록 DEV_KSIC_TOKENS에 “소프트웨어 도매업”을 추가하고 대기열을 다시 만들었습니다. 같은 코드의 12곳이 대기열에서 빠졌고, 재빌드한 대기열에 남은 G4651 회사는 0곳이었습니다. “컴퓨터 제조업”은 목록에 넣지 않았습니다. 하드웨어를 만드는 제조사는 원래 저희가 메일을 보내려던 대상이기 때문입니다.
- 업종코드 낱말 목록: “소프트웨어 도매업” 1줄 추가, “컴퓨터 제조업”은 보존
- 업태·종목 문구 필터: 구현한 코드를 커밋하지 않고 되돌림
- 기각 근거: 후보 4,249곳 중 108곳 오탐이라는 실측 수치와 함께 개인화 페이지 설계 문서의 “기각된 보강안” 절에 보존
- 테스트: 낱말 추가로 어긋난 기존 테스트를 새 목록에 맞게 정리
버린 보강안을 문서에 남긴 데는 이유가 있습니다. “라벨 말고 문구를 읽자”는 생각은 누구에게나 자연스럽게 떠오르는 개선안이라, 기록이 없으면 몇 주 뒤 같은 안을 다시 구현하게 됩니다. 108곳이라는 숫자와 그 목록의 업종을 함께 적어 두면, 다음 사람은 구현하기 전에 왜 안 되는지부터 확인할 수 있습니다.
발송 제외 목록에 막혀 있던 클릭 회사 11곳은 주석 처리해 막힘을 풀었습니다. 다만 대기업이 새로 대기열로 들어오는 길은 규모 필터가 계속 막습니다. 직원 수 상한 50명(ICP_MAX_EMPLOYEES=50)과 매출 상한 500억 원(ICP_MAX_REVENUE_EOK=500)입니다. 클릭으로 관심을 보인 회사만 예외로 두고, 처음 보내는 대상에는 규모 기준을 그대로 적용하는 구조입니다.
막힘을 풀지 말자는 반대 안도 검토했습니다. 클릭한 회사에도 기존 대기업 제한을 그대로 두면 규칙은 한 줄도 바뀌지 않습니다. 하지만 그 안은 회사가 먼저 보여 준 관심이라는 유일한 실증을 스스로 버리는 선택이었습니다. 클릭한 회사는 저희가 찾아간 대상이 아니라 찾아온 수요에 가깝고, 마침 회사 이름이 들어간 안내 페이지가 막 새로 열린 시점이라 다시 연락하기에 가장 좋은 때였습니다. 그래서 제한을 유지하는 안은 버렸습니다.
재접촉에서도 끝까지 빼야 하는 회사는 따로 지켰습니다. 수신거부를 요청한 1곳, 그리고 webmaster나 privacy 같은 관리용 주소 3곳은 어떤 경우에도 다시 보내지 않습니다. 이렇게 정리한 재접촉 대상 21곳을 8월 14일 오전 9시 발송으로 예약했습니다. 같은 날 하루 발송 상한도 100통에서 150통으로 한 단계 올렸습니다. 반송률 4.3%가 저희가 잡은 안전선 8%의 절반이었고, 200통으로 바로 2배를 올리는 안은 스팸 필터가 발신자를 익히는 단계적 증량의 취지에 어긋나 버렸습니다.
다시 재 보니 결과는 어땠나?
필터 쪽 결과는 바로 확인했습니다. 낱말을 추가하고 다시 만든 대기열에서 업종코드 G4651인 회사는 0곳이었습니다. 고치기 전 12곳이 남아 있던 자리입니다. 문구 필터를 붙였다면 4,249곳 중 108곳이 추가로 빠졌을 텐데, 그 108곳은 지금도 대기열 후보로 남아 있습니다.

나흘 뒤인 8월 17일에는 발송 전체를 다시 셌습니다. 메일 하나에 여러 번 찍힌 기록을 가장 많이 진행된 단계 하나로 접어서 센 결과, 실제 발송은 1,193건이었습니다. 그중 배달 895건, 열람 177건, 클릭 56건, 반송 60건이었고, 클릭 56건은 서로 다른 회사 37곳에서 나왔습니다.

그리고 폼 문의는 0건이었습니다. 같은 기간 들어온 고유 리드 14건은 전부 검색과 광고에서 왔고, 영업 메일에서 온 리드는 하나도 없었습니다. 클릭한 37곳에는 다국적 기업의 한국 지사가 섞여 있었고, 받은 주소도 customerservice, webmaster, info 같은 공용 메일함이 많았습니다. 필터를 고쳐 개발사는 걸렀지만, 대상 고르기 자체가 아직 정확하지 않았다는 신호입니다.
| 항목 | 고치기 전 | 고친 뒤 |
|---|---|---|
| 개발사 판정 기준 | 업종코드 낱말 목록 (“도매업” 형태 없음) | 같은 목록 + “소프트웨어 도매업” |
| 대기열의 G4651 회사 | 12곳 | 0곳 |
| 업태·종목 문구 필터 | 없음 | 구현 후 기각 (4,249곳 중 108곳 오탐) |
| 클릭했지만 막힌 회사 | 34곳 중 11곳 | 막힘 해제, 재접촉 21곳 예약 |
| 하루 발송 상한 | 100통 | 150통 (200통은 2주 뒤 재검토) |
| 영업 메일발 폼 문의 | 0건 (클릭 61건 시점) | 0건 (8월 17일, 클릭 56건) |
표의 마지막 줄 두 숫자는 출처가 다릅니다. 61건은 8월 13일 시점 클릭 기록을 그대로 센 값이고, 56건은 8월 17일에 메일 한 통을 한 번만 세도록 기록을 접은 값입니다. 셈법이 달라 둘을 바로 비교하면 안 됩니다. 두 셈법 모두에서 문의가 0건이라는 점은 같습니다.
남는 한계는 무엇인가?
라벨이 실체와 다른 회사는 앞으로도 통과할 수 있습니다. 이번에는 도매업 코드로 등록한 개발사였지만, 다른 코드로 등록한 개발사가 나오면 낱말 목록은 그 회사를 모릅니다. 이 잔여 위험은 발송 전 대기열을 사람이 훑어보는 단계와 받는 회사의 반응으로 받아 내기로 했습니다. 이번 구멍도 결국 사람의 눈이 찾았습니다.
이 선택은 두 오류의 비용을 맞바꾼 결과입니다. 문구 필터를 켜면 노리던 중소 제조사 108곳을 잃고, 끄면 라벨이 틀린 개발사 몇 곳에 맞지 않는 메일이 한 통씩 나갑니다. 매출 기회 108곳이 부적합 메일 몇 통보다 비싸다고 판단했습니다. 다만 “몇 곳”이 실제로 몇 곳인지는 세지 못했습니다. 라벨이 틀린 개발사를 전수로 찾을 방법이 없기 때문입니다.
반대 방향의 과차단도 남아 있습니다. “소프트웨어 도매업”을 막으면서 정말로 소프트웨어를 사다 파는 유통사까지 함께 빠집니다. “애매하면 막는 쪽이 안전하다”는 원칙에 맞춰 받아들였지만, 그렇게 빠진 유통사가 몇 곳인지는 따로 재지 않았습니다. 12곳 가운데 실제 개발사와 순수 유통사의 비율도 확인하지 않았습니다.
가장 큰 한계는 필터가 문의 0건을 풀지 못했다는 점입니다. 필터는 보내면 안 되는 회사를 빼 줄 뿐, 받은 회사가 답하게 만들지는 않습니다. 클릭 56건, 문의 0건이라는 숫자는 대상보다 메일 내용과 착지 페이지 쪽 질문으로 넘어가야 할 문제였습니다. 하루 상한 200통은 2주 뒤 반송률과 신고를 다시 재서 정하기로 미뤄 두었는데, 문의가 0건인 상태에서는 발송량을 늘려도 같은 결과가 커질 뿐입니다.
업종코드 필터는 어디까지 믿어야 하나?
이번 일에서 남은 기준은 세 가지입니다. 첫째, 업종코드 필터는 코드 단위로 틀리므로 구멍 하나를 찾으면 같은 코드 전체를 세어 봅니다. 한 곳을 빼고 끝내면 나머지가 같은 길로 나갑니다. 둘째, 정보가 많아 보이는 텍스트 필드를 판정에 넣기 전에, 그 필드가 실체를 적는 칸인지 등록 항목을 나열하는 칸인지부터 확인합니다.
셋째, 필터를 고친 뒤에는 빠진 숫자만 보지 말고 빠진 목록을 직접 엽니다. 이번에 108곳이라는 숫자는 성과처럼 보였고, 목록을 열어 봐야만 종이제품 제조사가 보였습니다. 걸러 낸 결과가 맞는지는 개수가 아니라 이름과 업종에서 드러납니다. 필터가 스스로 확인하지 못하는 부분을 사람이 확인하는 자리를 일부러 남겨 두는 편이 낫습니다.
기업 데이터로 영업 대상이나 고객 분류 규칙을 만들고 있다면, 업종코드와 사업자등록 문구 중 어디에 판정을 걸지부터 이 순서로 따져 보길 권합니다. 비슷한 분류 규칙이나 대상 선정 자동화를 설계하는 중이라면 상담 페이지에서 문의를 남길 수 있습니다.