Skip to content

email 邮箱输入

type="email" 是 HTML5 专为邮箱地址设计的输入控件。浏览器不仅会为移动设备提供优化的虚拟键盘(包含 @.com 快捷键),还会在表单提交时自动验证输入值是否符合邮箱格式。本节将详细讲解邮箱输入的验证机制、multiple 属性的多邮箱模式,以及使用 pattern 进行补充验证。

前置知识

阅读本节前,建议先了解:password 密码输入

基础概念

什么是 email 输入

type="email" 创建一个专门用于输入电子邮件地址的输入框。它在功能上与 type="text" 相似,但增加了:

  1. 自动格式验证:提交时浏览器检查是否为合法邮箱格式
  2. 移动端键盘优化:在手机上弹出包含 @. 的邮箱键盘
  3. 语义化:辅助技术可以正确识别这是一个邮箱输入框
html
<!-- 基本 email 输入 -->
<input type="email" name="email" placeholder="user@example.com">

<!-- 自动验证:提交时检查格式 -->
<form>
  <input type="email" name="email" required>
  <!-- 输入 "hello" 提交时,浏览器会阻止并提示 -->
  <!-- 输入 "hello@example.com" 提交时,验证通过 -->
  <button type="submit">提交</button>
</form>

email 的核心特征

特征说明
输入方式键盘输入
数据类型邮箱地址字符串
自动验证是(检查是否包含 @ 和域名)
移动端键盘邮箱键盘(含 @.com
支持属性与 text 相同 + multiple

语法

基本语法

html
<input
  type="email"
  name="email"
  id="email"
  placeholder="user@example.com"
  required
  multiple
  autocomplete="email"
  pattern="自定义正则"
  list="datalistId"
>

专有/常用属性

属性说明
type"email"指定为邮箱输入
multiple布尔属性允许输入多个邮箱(逗号分隔)
autocomplete"email"自动补全为邮箱地址
pattern正则表达式自定义验证规则(补充浏览器默认验证)

详细说明

浏览器自动验证规则

浏览器对 type="email" 的默认验证规则比较宽松,只检查值是否符合 value@domain 的基本格式:

验证通过的示例:

  • user@example.com
  • test@sub.domain.org
  • a@b.c (最短的有效格式)

验证失败的示例:

  • user (缺少 @ 和域名)
  • user@ (缺少域名)
  • @example.com (缺少用户名)
  • user@@example.com (多个 @
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>email 自动验证</title>
  <style>
    label { display: block; margin-bottom: 4px; font-weight: 500; }
    input { padding: 8px; border: 1px solid #ccc; border-radius: 4px; width: 300px; }
    .demo { margin-bottom: 20px; padding: 12px; border: 1px solid #e0e0e0; border-radius: 8px; }
  </style>
</head>
<body>
  <h2>email 自动验证演示</h2>

  <div class="demo">
    <p>浏览器默认验证比较宽松,只检查基本格式:</p>
    <form>
      <label for="email1">输入邮箱后点击提交:</label>
      <input type="email" id="email1" name="email" required>
      <button type="submit">验证</button>
    </form>
    <p style="color: #999; font-size: 13px; margin-top: 8px;">
      试试输入 "hello"(失败)和 "hello@world.com"(成功)
    </p>
  </div>

  <!--
    以下值都会通过浏览器的默认验证(可能不符合实际邮箱规则):
    - a@b.c          (极短的域名)
    - user@localhost  (没有点号)
    - user@192.168.1.1 (IP 地址域名)
  -->
</body>
</html>

关于验证宽松性

浏览器的默认邮箱验证故意设计得比较宽松,因为邮箱格式的完整规范(RFC 5322)非常复杂,严格验证会拒绝很多合法的邮箱地址。如果需要更严格的验证,应使用 pattern 属性或 JavaScript。

multiple 多邮箱模式

multiple 属性允许用户在一个输入框中输入多个邮箱地址,用逗号分隔。提交时,整个字符串作为一个字段值发送。

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>multiple 多邮箱</title>
  <style>
    .form-group { margin-bottom: 16px; }
    label { display: block; font-weight: 500; margin-bottom: 6px; }
    input { width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 6px; box-sizing: border-box; }
    .hint { font-size: 13px; color: #999; margin-top: 4px; }
  </style>
</head>
<body>
  <h2>发送邮件邀请</h2>
  <form action="/api/invite" method="post">
    <div class="form-group">
      <label for="to">收件人(多个邮箱用逗号分隔)</label>
      <input type="email"
             id="to"
             name="to"
             multiple
             required
             placeholder="a@example.com, b@example.com, c@example.com">
      <p class="hint">多个邮箱地址之间用逗号分隔</p>
    </div>

    <div class="form-group">
      <label for="subject">主题</label>
      <input type="text" id="subject" name="subject" placeholder="邀请标题">
    </div>

    <button type="submit">发送邀请</button>
  </form>

  <!--
    提交时 to 字段的值:
    to=a%40example.com%2C+b%40example.com%2C+c%40example.com

    服务器解码后:
    to = "a@example.com, b@example.com, c@example.com"

    服务器需要用逗号分割来获取各个邮箱地址
  -->
</body>
</html>

multiple 的验证行为

当使用 multiple 时,浏览器会验证每个逗号分隔的值都是合法邮箱。例如 "a@b.com, invalid, c@d.com" 会导致验证失败,因为中间的 invalid 不是合法邮箱。

pattern 正则补充验证

如果浏览器的默认验证不够严格,可以使用 pattern 属性添加自定义正则规则。

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>pattern 补充验证</title>
  <style>
    .form-group { margin-bottom: 20px; }
    label { display: block; font-weight: 500; margin-bottom: 6px; }
    input {
      width: 100%;
      max-width: 400px;
      padding: 10px 12px;
      border: 1px solid #ccc;
      border-radius: 6px;
      box-sizing: border-box;
    }

    /* 实时验证样式 */
    input:valid:not(:placeholder-shown) {
      border-color: #27ae60;
    }

    input:invalid:not(:placeholder-shown):not(:focus) {
      border-color: #e74c3c;
    }

    .hint { font-size: 13px; color: #999; margin-top: 4px; }
  </style>
</head>
<body>
  <h2>邮箱注册</h2>
  <form action="/register" method="post">
    <!-- 基本邮箱验证(浏览器默认) -->
    <div class="form-group">
      <label for="email1">基本验证(浏览器默认)</label>
      <input type="email" id="email1" name="email" required
             placeholder="如 user@example.com">
      <p class="hint">浏览器自动验证,只检查基本格式</p>
    </div>

    <!--
      严格验证:限制为常见邮箱格式
      - 用户名部分:字母、数字、点、下划线、连字符
      - 域名部分:至少一个点号分隔
      - 顶级域名:至少2个字母
    -->
    <div class="form-group">
      <label for="email2">严格验证(pattern 补充)</label>
      <input type="email"
             id="email2"
             name="email_strict"
             required
             pattern="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
             title="请输入有效的邮箱地址,如 user@example.com"
             placeholder="如 user@example.com">
      <p class="hint">要求:标准邮箱格式,域名至少包含一个点号</p>
    </div>

    <!--
      限制企业邮箱后缀
      只允许以 @company.com 结尾的邮箱
    -->
    <div class="form-group">
      <label for="email3">企业邮箱(仅限 company.com)</label>
      <input type="email"
             id="email3"
             name="company_email"
             required
             pattern="^[a-zA-Z0-9._%+-]+@company\.com$"
             title="请使用 company.com 的企业邮箱"
             placeholder="如 zhangsan@company.com">
      <p class="hint">仅接受 @company.com 结尾的企业邮箱</p>
    </div>

    <button type="submit">注册</button>
  </form>
</body>
</html>

与 datalist 配合

type="email" 也可以配合 list 属性和 <datalist> 提供邮箱建议:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>email 与 datalist</title>
</head>
<body>
  <form action="/invite" method="post">
    <label for="inviteEmail">邀请邮箱:</label>
    <input type="email"
           id="inviteEmail"
           name="email"
           list="knownEmails"
           placeholder="输入或选择邮箱"
           multiple>

    <!-- 常用联系人邮箱列表 -->
    <datalist id="knownEmails">
      <option value="alice@example.com">
      <option value="bob@example.com">
      <option value="charlie@company.com">
      <option value="david@company.com">
    </datalist>

    <button type="submit">发送邀请</button>
  </form>
</body>
</html>

验证 API 的使用

type="email" 的验证结果可以通过 JavaScript 的 Constraint Validation API 获取:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>email 验证 API</title>
</head>
<body>
  <form id="emailForm">
    <label for="email">邮箱:</label>
    <input type="email" id="email" name="email" required>

    <button type="submit">提交</button>
  </form>

  <div id="result"></div>

  <script>
    const form = document.getElementById('emailForm');
    const emailInput = document.getElementById('email');
    const result = document.getElementById('result');

    // 实时验证
    emailInput.addEventListener('input', function() {
      const validity = this.validity;

      if (validity.valueMissing) {
        result.textContent = '邮箱不能为空';
        result.style.color = '#e74c3c';
      } else if (validity.typeMismatch) {
        result.textContent = '请输入有效的邮箱地址';
        result.style.color = '#e74c3c';
      } else if (this.value && validity.valid) {
        result.textContent = '邮箱格式正确';
        result.style.color = '#27ae60';
      } else {
        result.textContent = '';
      }
    });

    // 提交验证
    form.addEventListener('submit', function(e) {
      e.preventDefault();

      if (form.checkValidity()) {
        result.textContent = '验证通过,准备提交:' + emailInput.value;
        result.style.color = '#27ae60';
      } else {
        form.reportValidity();
      }
    });
  </script>
</body>
</html>

实战示例

带域后缀自动补全的邮箱输入

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>邮箱域后缀补全</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      max-width: 500px;
      margin: 40px auto;
      padding: 20px;
    }

    .form-group {
      margin-bottom: 20px;
    }

    label {
      display: block;
      font-weight: 500;
      margin-bottom: 6px;
    }

    input {
      width: 100%;
      padding: 10px 12px;
      border: 1px solid #ddd;
      border-radius: 6px;
      box-sizing: border-box;
      font-size: 14px;
    }

    input:focus {
      outline: none;
      border-color: #4a90d9;
    }

    .suggestion-list {
      list-style: none;
      padding: 0;
      margin: 4px 0 0;
      border: 1px solid #ddd;
      border-top: none;
      border-radius: 0 0 6px 6px;
      display: none;
      max-height: 150px;
      overflow-y: auto;
    }

    .suggestion-list.active {
      display: block;
    }

    .suggestion-list li {
      padding: 8px 12px;
      cursor: pointer;
      font-size: 14px;
    }

    .suggestion-list li:hover,
    .suggestion-list li.highlighted {
      background-color: #f0f7ff;
    }
  </style>
</head>
<body>
  <h2>注册</h2>
  <form action="/register" method="post">
    <div class="form-group">
      <label for="email">邮箱地址</label>
      <div style="position: relative;">
        <input type="email"
               id="email"
               name="email"
               required
               autocomplete="email"
               placeholder="请输入邮箱">
        <ul class="suggestion-list" id="suggestions"></ul>
      </div>
    </div>

    <button type="submit">注册</button>
  </form>

  <script>
    const emailInput = document.getElementById('email');
    const suggestionList = document.getElementById('suggestions');

    // 常见邮箱域名后缀
    const domains = [
      'qq.com', '163.com', '126.com', 'gmail.com',
      'outlook.com', 'hotmail.com', 'yahoo.com',
      'sina.com', 'foxmail.com', 'icloud.com'
    ];

    emailInput.addEventListener('input', function() {
      const value = this.value.trim();
      suggestionList.innerHTML = '';

      if (!value || value.includes('@')) {
        suggestionList.classList.remove('active');
        return;
      }

      // 生成建议列表
      const fragment = document.createDocumentFragment();
      domains.forEach(domain => {
        const li = document.createElement('li');
        li.textContent = value + '@' + domain;
        li.addEventListener('mousedown', function(e) {
          e.preventDefault();
          emailInput.value = this.textContent;
          suggestionList.classList.remove('active');
        });
        fragment.appendChild(li);
      });

      suggestionList.appendChild(fragment);
      suggestionList.classList.add('active');
    });

    // 点击外部关闭建议列表
    document.addEventListener('click', function(e) {
      if (!e.target.closest('.form-group')) {
        suggestionList.classList.remove('active');
      }
    });

    // 失去焦点时延迟关闭(允许 mousedown 事件先执行)
    emailInput.addEventListener('blur', function() {
      setTimeout(() => {
        suggestionList.classList.remove('active');
      }, 200);
    });
  </script>
</body>
</html>

注意事项

  1. 浏览器验证不检查邮箱是否存在type="email" 只验证格式,不会验证邮箱地址是否真实存在或可以接收邮件。邮箱存在性检查需要通过服务器端发送验证邮件。

  2. pattern 验证比 type 验证更严格:如果同时设置了 type="email"pattern,浏览器会先检查 pattern。pattern 的错误提示不会自动说明是邮箱格式问题,需要通过 title 属性补充说明。

  3. multiple 的提交格式:使用 multiple 时,所有邮箱以逗号拼接成一个字符串。服务器端需要手动分割。

  4. 移动端键盘因系统而异:iOS 和 Android 的邮箱键盘外观不同,但都包含 @. 快捷键。

  5. email 字段支持空值:如果未设置 required,空输入会通过验证。只有非空的值才会被检查邮箱格式。

最佳实践

  1. 使用 type="email" 而非 type="text":即使是简单的邮箱输入,也使用正确的 type,以获得自动验证和移动端优化。

  2. 对于企业邮箱使用 pattern 限制后缀:如果只接受特定域名的邮箱,使用 pattern 属性。

  3. 为 email 设置 autocomplete="email":帮助浏览器正确保存和填充邮箱地址。

  4. 不要过度限制 pattern:过于严格的正则可能拒绝合法的邮箱地址。浏览器默认的宽松验证通常是合理的选择。

  5. 服务器端验证是必须的:客户端验证可以被绕过,始终在服务器端验证邮箱格式和唯一性。

下一节

继续学习:number 数字输入

参考链接