테스트 중에 우연히? 시스템에서 hello@gmail.com 이 유효하지 않은 이메일이라고 오류를 뱉길래 뭐지? 하고 관련 내용을 뜯어보고 깨달은 내용을 정리한다.

처음에 필자는 이 건 당연히 로직의 버그라고 생각을 했었다. 해당 건을 당당히 이슈로 등록하려다가 돌다리도 두들겨 보고 가자는 마음으로 일단 관련 로직을 한 번 확인해 보기로 했다. 현재 진행하는 프로젝트에서 email 검증은 class-validator 에서 제공하는 isEmail() 함수를 사용하고 있었다. 해당 함수는 validator 모듈에서 제공하는 isEmail() 함수였다.

validator 의 테스트케이스hello@gmail.com 를 직접 넣고 돌려 보았다.

  it.only('should validate email addresses with domain specific validation', () => {
    test({
      validator: 'isEmail',
      args: [{ domain_specific_validation: true }],
      valid: [
        'foo@bar.com',
        'hello@gmail.com',
      ],
      invalid: [
        `${repeat('a', 31)}@gmail.com`,
        'test@gmail.com',
        'test.1@gmail.com',
      ],
    });
  });

역시나 아래와 같이 오류가 발생했다. 좋다! 물증 확보!

> validator@10.11.0 test /Users/mac9/project/open-src/validator.js
> mocha --require @babel/register

  Validators
    1) should validate email addresses with domain specific validation


  0 passing (127ms)
  1 failing

  1) Validators
       should validate email addresses with domain specific validation:
     Error: validator.isEmail(hello@gmail.com, [object Object]) failed but should have passed
      at /Users/mac9/project/open-src/validator.js/test/validators.js:20:15
      at Array.forEach (<anonymous>)
      at forEach (test/validators.js:13:19)
      at Context.test (test/validators.js:107:5)


npm ERR! Test failed.  See above for more details.

Process finished with exit code 1

해당 소스를 열어보았다.

// ...
export default function isEmail(str, options) {
  assertString(str);
  options = merge(options, default_email_options);
// ...
  if (options.domain_specific_validation && (lower_domain === 'gmail.com' || lower_domain === 'googlemail.com')) {
    /*
      Previously we removed dots for gmail addresses before validating.
      This was removed because it allows `multiple..dots@gmail.com`
      to be reported as valid, but it is not.
      Gmail only normalizes single dots, removing them from here is pointless,
      should be done in normalizeEmail
    */
    user = user.toLowerCase();

    // Removing sub-address from username before gmail validation
    const username = user.split('+')[0];

    // Dots are not included in gmail length restriction
    if (!isByteLength(username.replace('.', ''), { min: 6, max: 30 })) {
      return false;
    }

    const user_parts = username.split('.');
    for (let i = 0; i < user_parts.length; i++) {
      if (!gmailUserPart.test(user_parts[i])) {
        return false;
      }
    }
  }
// ...  

뭔가 있었다..

{ min: 6, max: 30 }

gmail 만의 특별한 제약이 있었던 것이다. 뜨으..;


validator 의 저 당당한 주간 다운로드 수를 보라


많은 사람들이 쓰는데는 다 이유가 있다. 고민하지 말고 validator 쓰자. 또 쓰자.