tempmail-sdk 1.0.3 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +51 -3
  2. package/bun.lock +60 -0
  3. package/demo/poll-emails.ts +7 -8
  4. package/dist/config.d.ts +47 -0
  5. package/dist/config.js +68 -0
  6. package/dist/index.d.ts +21 -20
  7. package/dist/index.js +101 -37
  8. package/dist/normalize.js +28 -3
  9. package/dist/providers/awamail.d.ts +2 -2
  10. package/dist/providers/awamail.js +1 -1
  11. package/dist/providers/chatgpt-org-uk.d.ts +2 -2
  12. package/dist/providers/chatgpt-org-uk.js +1 -1
  13. package/dist/providers/dropmail.d.ts +2 -2
  14. package/dist/providers/dropmail.js +1 -1
  15. package/dist/providers/guerrillamail.d.ts +22 -0
  16. package/dist/providers/guerrillamail.js +71 -0
  17. package/dist/providers/linshi-email.d.ts +2 -2
  18. package/dist/providers/linshi-email.js +1 -1
  19. package/dist/providers/mail-tm.d.ts +2 -2
  20. package/dist/providers/mail-tm.js +1 -1
  21. package/dist/providers/maildrop.d.ts +21 -0
  22. package/dist/providers/maildrop.js +180 -0
  23. package/dist/providers/temp-mail-io.d.ts +2 -2
  24. package/dist/providers/temp-mail-io.js +1 -1
  25. package/dist/providers/tempmail-la.d.ts +2 -2
  26. package/dist/providers/tempmail-la.js +1 -1
  27. package/dist/providers/tempmail-lol.d.ts +2 -2
  28. package/dist/providers/tempmail-lol.js +1 -1
  29. package/dist/providers/tempmail.d.ts +2 -2
  30. package/dist/providers/tempmail.js +1 -1
  31. package/dist/retry.js +14 -5
  32. package/dist/types.d.ts +14 -15
  33. package/dist/types.js +1 -1
  34. package/package.json +1 -1
  35. package/src/config.ts +82 -0
  36. package/src/index.ts +102 -39
  37. package/src/normalize.ts +30 -2
  38. package/src/providers/awamail.ts +2 -2
  39. package/src/providers/chatgpt-org-uk.ts +2 -2
  40. package/src/providers/dropmail.ts +2 -2
  41. package/src/providers/guerrillamail.ts +78 -0
  42. package/src/providers/linshi-email.ts +2 -2
  43. package/src/providers/mail-tm.ts +2 -2
  44. package/src/providers/maildrop.ts +210 -0
  45. package/src/providers/temp-mail-io.ts +2 -2
  46. package/src/providers/tempmail-la.ts +2 -2
  47. package/src/providers/tempmail-lol.ts +2 -2
  48. package/src/providers/tempmail.ts +2 -2
  49. package/src/retry.ts +15 -4
  50. package/src/types.ts +15 -15
@@ -1,4 +1,4 @@
1
- import { EmailInfo, Email, Channel } from '../types';
1
+ import { InternalEmailInfo, Email, Channel } from '../types';
2
2
  import { normalizeEmail } from '../normalize';
3
3
 
4
4
  const CHANNEL: Channel = 'chatgpt-org-uk';
@@ -15,7 +15,7 @@ const DEFAULT_HEADERS = {
15
15
  'DNT': '1',
16
16
  };
17
17
 
18
- export async function generateEmail(): Promise<EmailInfo> {
18
+ export async function generateEmail(): Promise<InternalEmailInfo> {
19
19
  const response = await fetch(`${BASE_URL}/generate-email`, {
20
20
  method: 'GET',
21
21
  headers: DEFAULT_HEADERS,
@@ -1,4 +1,4 @@
1
- import { EmailInfo, Email, Channel } from '../types';
1
+ import { InternalEmailInfo, Email, Channel } from '../types';
2
2
  import { normalizeEmail } from '../normalize';
3
3
 
4
4
  const CHANNEL: Channel = 'dropmail';
@@ -53,7 +53,7 @@ async function graphqlRequest(query: string, variables?: Record<string, any>): P
53
53
  * GraphQL mutation: introduceSession
54
54
  * 返回 session ID (存入 token) 和邮箱地址
55
55
  */
56
- export async function generateEmail(): Promise<EmailInfo> {
56
+ export async function generateEmail(): Promise<InternalEmailInfo> {
57
57
  const data = await graphqlRequest(CREATE_SESSION_QUERY);
58
58
 
59
59
  const session = data?.introduceSession;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Guerrilla Mail 渠道实现
3
+ * API 文档: https://www.guerrillamail.com/GuerrillaMailAPI.html
4
+ *
5
+ * 特点:
6
+ * - 无需认证,公开 JSON API
7
+ * - 通过 sid_token 维持会话
8
+ * - 邮箱有效期 60 分钟
9
+ */
10
+
11
+ import { InternalEmailInfo, Email, Channel } from '../types';
12
+ import { normalizeEmail } from '../normalize';
13
+
14
+ const CHANNEL: Channel = 'guerrillamail';
15
+ const BASE_URL = 'https://api.guerrillamail.com/ajax.php';
16
+
17
+ /**
18
+ * 创建临时邮箱
19
+ * API: GET ajax.php?f=get_email_address
20
+ * 返回 email_addr + sid_token(用于后续获取邮件)
21
+ */
22
+ export async function generateEmail(): Promise<InternalEmailInfo> {
23
+ const response = await fetch(`${BASE_URL}?f=get_email_address&lang=en`, {
24
+ method: 'GET',
25
+ headers: {
26
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
27
+ },
28
+ });
29
+
30
+ if (!response.ok) {
31
+ throw new Error(`Failed to generate email: ${response.status}`);
32
+ }
33
+
34
+ const data = await response.json();
35
+
36
+ if (!data.email_addr || !data.sid_token) {
37
+ throw new Error('Failed to generate email: missing email_addr or sid_token');
38
+ }
39
+
40
+ return {
41
+ channel: CHANNEL,
42
+ email: data.email_addr,
43
+ token: data.sid_token,
44
+ expiresAt: data.email_timestamp ? (data.email_timestamp + 3600) * 1000 : undefined,
45
+ };
46
+ }
47
+
48
+ /**
49
+ * 获取邮件列表
50
+ * API: GET ajax.php?f=check_email&seq=0&sid_token=xxx
51
+ * 返回 list 数组,每个元素包含 mail_id, mail_from, mail_subject, mail_body 等
52
+ */
53
+ export async function getEmails(token: string, email: string): Promise<Email[]> {
54
+ const response = await fetch(`${BASE_URL}?f=check_email&seq=0&sid_token=${encodeURIComponent(token)}`, {
55
+ method: 'GET',
56
+ headers: {
57
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
58
+ },
59
+ });
60
+
61
+ if (!response.ok) {
62
+ throw new Error(`Failed to get emails: ${response.status}`);
63
+ }
64
+
65
+ const data = await response.json();
66
+ const list = Array.isArray(data.list) ? data.list : [];
67
+
68
+ return list.map((item: any) => normalizeEmail({
69
+ id: item.mail_id,
70
+ from: item.mail_from,
71
+ to: email,
72
+ subject: item.mail_subject,
73
+ text: item.mail_body || item.mail_excerpt || '',
74
+ html: item.mail_body || '',
75
+ date: item.mail_date || '',
76
+ isRead: item.mail_read === 1,
77
+ }, email));
78
+ }
@@ -1,4 +1,4 @@
1
- import { EmailInfo, Email, Channel } from '../types';
1
+ import { InternalEmailInfo, Email, Channel } from '../types';
2
2
  import { normalizeEmail } from '../normalize';
3
3
 
4
4
  const CHANNEL: Channel = 'linshi-email';
@@ -16,7 +16,7 @@ const DEFAULT_HEADERS = {
16
16
  'DNT': '1',
17
17
  };
18
18
 
19
- export async function generateEmail(): Promise<EmailInfo> {
19
+ export async function generateEmail(): Promise<InternalEmailInfo> {
20
20
  const response = await fetch(`${BASE_URL}/email/${API_KEY}`, {
21
21
  method: 'POST',
22
22
  headers: DEFAULT_HEADERS,
@@ -1,4 +1,4 @@
1
- import { EmailInfo, Email, Channel } from '../types';
1
+ import { InternalEmailInfo, Email, Channel } from '../types';
2
2
  import { normalizeEmail } from '../normalize';
3
3
 
4
4
  const CHANNEL: Channel = 'mail-tm';
@@ -88,7 +88,7 @@ async function getToken(address: string, password: string): Promise<string> {
88
88
  * 创建临时邮箱
89
89
  * 流程: 获取域名 → 生成随机邮箱/密码 → 创建账号 → 获取 Token
90
90
  */
91
- export async function generateEmail(): Promise<EmailInfo> {
91
+ export async function generateEmail(): Promise<InternalEmailInfo> {
92
92
  // 1. 获取可用域名
93
93
  const domains = await getDomains();
94
94
  if (domains.length === 0) {
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Maildrop 渠道实现
3
+ * API: GraphQL endpoint https://api.maildrop.cc/graphql
4
+ *
5
+ * 特点:
6
+ * - 无需认证,公开 GraphQL API
7
+ * - 自带反垃圾过滤
8
+ * - 邮箱名即用户名(任意字符串@maildrop.cc)
9
+ * - 无过期时间限制
10
+ */
11
+
12
+ import { InternalEmailInfo, Email, Channel } from '../types';
13
+
14
+ const CHANNEL: Channel = 'maildrop';
15
+ const GRAPHQL_URL = 'https://api.maildrop.cc/graphql';
16
+ const DOMAIN = 'maildrop.cc';
17
+
18
+ /**
19
+ * 解码 RFC 2047 编码的邮件头(如发件人、主题)
20
+ * 支持 Base64 (B) 和 Quoted-Printable (Q) 编码
21
+ */
22
+ function decodeRfc2047(str: string): string {
23
+ if (!str) return '';
24
+ return str.replace(/=\?([^?]+)\?(B|Q)\?([^?]*)\?=/gi, (_, charset, encoding, encoded) => {
25
+ try {
26
+ if (encoding.toUpperCase() === 'B') {
27
+ return Buffer.from(encoded, 'base64').toString('utf-8');
28
+ }
29
+ /* Quoted-Printable: _=空格,=XX=十六进制字节 */
30
+ const decoded = encoded
31
+ .replace(/_/g, ' ')
32
+ .replace(/=([0-9A-Fa-f]{2})/g, (_m: string, hex: string) => String.fromCharCode(parseInt(hex, 16)));
33
+ return decoded;
34
+ } catch {
35
+ return encoded;
36
+ }
37
+ });
38
+ }
39
+
40
+ /**
41
+ * 从原始 MIME 邮件源码中提取纯文本正文
42
+ * maildrop 的 data 字段返回完整 MIME 源码,需要解析出 text/plain 部分
43
+ */
44
+ function extractTextFromMime(raw: string): string {
45
+ if (!raw) return '';
46
+
47
+ /* 分离邮件头和正文(双换行分隔) */
48
+ const headerBodySplit = raw.indexOf('\r\n\r\n');
49
+ if (headerBodySplit === -1) return raw;
50
+
51
+ const headers = raw.substring(0, headerBodySplit);
52
+ const body = raw.substring(headerBodySplit + 4);
53
+
54
+ /* 检查是否为 multipart 邮件 */
55
+ const boundaryMatch = headers.match(/boundary="?([^";\r\n]+)"?/i);
56
+ if (boundaryMatch) {
57
+ const boundary = boundaryMatch[1];
58
+ const parts = body.split('--' + boundary);
59
+
60
+ for (const part of parts) {
61
+ /* 查找 text/plain 部分 */
62
+ if (part.match(/Content-Type:\s*text\/plain/i)) {
63
+ const partHeaderEnd = part.indexOf('\r\n\r\n');
64
+ if (partHeaderEnd === -1) continue;
65
+
66
+ const partHeaders = part.substring(0, partHeaderEnd);
67
+ let content = part.substring(partHeaderEnd + 4).replace(/\r\n$/, '').replace(/--$/, '').trim();
68
+
69
+ /* 处理 Content-Transfer-Encoding */
70
+ if (partHeaders.match(/Content-Transfer-Encoding:\s*base64/i)) {
71
+ try {
72
+ content = Buffer.from(content.replace(/\s/g, ''), 'base64').toString('utf-8');
73
+ } catch { /* 解码失败则保留原文 */ }
74
+ } else if (partHeaders.match(/Content-Transfer-Encoding:\s*quoted-printable/i)) {
75
+ content = content
76
+ .replace(/=\r?\n/g, '')
77
+ .replace(/=([0-9A-Fa-f]{2})/g, (_, hex: string) => String.fromCharCode(parseInt(hex, 16)));
78
+ }
79
+
80
+ return content.trim();
81
+ }
82
+ }
83
+ }
84
+
85
+ /* 非 multipart:检查整体编码 */
86
+ if (headers.match(/Content-Transfer-Encoding:\s*base64/i)) {
87
+ try {
88
+ return Buffer.from(body.replace(/\s/g, ''), 'base64').toString('utf-8').trim();
89
+ } catch { /* 解码失败 */ }
90
+ }
91
+
92
+ return body.trim();
93
+ }
94
+
95
+ /**
96
+ * 生成随机用户名
97
+ */
98
+ function randomUsername(length: number = 10): string {
99
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
100
+ let result = '';
101
+ for (let i = 0; i < length; i++) {
102
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
103
+ }
104
+ return result;
105
+ }
106
+
107
+ /**
108
+ * 发送 GraphQL 请求
109
+ * 使用 operationName + variables 的标准 GraphQL 格式
110
+ */
111
+ async function graphqlRequest(
112
+ operationName: string,
113
+ query: string,
114
+ variables: Record<string, string> = {},
115
+ ): Promise<any> {
116
+ const response = await fetch(GRAPHQL_URL, {
117
+ method: 'POST',
118
+ headers: {
119
+ 'Content-Type': 'application/json',
120
+ 'Origin': 'https://maildrop.cc',
121
+ 'Referer': 'https://maildrop.cc/',
122
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
123
+ },
124
+ body: JSON.stringify({ operationName, variables, query }),
125
+ });
126
+
127
+ if (!response.ok) {
128
+ throw new Error(`Maildrop GraphQL request failed: ${response.status}`);
129
+ }
130
+
131
+ const data = await response.json();
132
+ if (data.errors && data.errors.length > 0) {
133
+ throw new Error(`Maildrop GraphQL error: ${data.errors[0].message}`);
134
+ }
135
+
136
+ return data.data;
137
+ }
138
+
139
+ /**
140
+ * 创建临时邮箱
141
+ * Maildrop 无需注册,任意用户名即可接收邮件
142
+ */
143
+ export async function generateEmail(): Promise<InternalEmailInfo> {
144
+ const username = randomUsername();
145
+ const email = `${username}@${DOMAIN}`;
146
+
147
+ /* 验证邮箱可用:查询一次 inbox 确认 API 正常 */
148
+ await graphqlRequest(
149
+ 'GetInbox',
150
+ 'query GetInbox($mailbox: String!) { inbox(mailbox: $mailbox) { id } }',
151
+ { mailbox: username },
152
+ );
153
+
154
+ return {
155
+ channel: CHANNEL,
156
+ email,
157
+ token: username,
158
+ };
159
+ }
160
+
161
+ /**
162
+ * 获取邮件列表
163
+ * 先查 inbox 获取邮件 ID 列表,再逐封获取完整内容
164
+ */
165
+ export async function getEmails(token: string, email: string): Promise<Email[]> {
166
+ const mailbox = token || email.split('@')[0];
167
+
168
+ /* 查询收件箱列表 */
169
+ const inboxData = await graphqlRequest(
170
+ 'GetInbox',
171
+ 'query GetInbox($mailbox: String!) { inbox(mailbox: $mailbox) { id headerfrom subject date } }',
172
+ { mailbox },
173
+ );
174
+
175
+ const inbox = inboxData?.inbox;
176
+ if (!Array.isArray(inbox) || inbox.length === 0) {
177
+ return [];
178
+ }
179
+
180
+ /* 逐封获取完整邮件内容 */
181
+ const emails: Email[] = [];
182
+ for (const item of inbox) {
183
+ try {
184
+ const msgData = await graphqlRequest(
185
+ 'GetMessage',
186
+ 'query GetMessage($mailbox: String!, $id: String!) { message(mailbox: $mailbox, id: $id) { id headerfrom subject date data html } }',
187
+ { mailbox, id: item.id },
188
+ );
189
+
190
+ const msg = msgData?.message;
191
+ if (msg) {
192
+ emails.push({
193
+ id: msg.id || item.id,
194
+ from: decodeRfc2047(msg.headerfrom || item.headerfrom || ''),
195
+ to: email,
196
+ subject: decodeRfc2047(msg.subject || item.subject || ''),
197
+ text: extractTextFromMime(msg.data || ''),
198
+ html: msg.html || '',
199
+ date: msg.date || item.date || '',
200
+ isRead: false,
201
+ attachments: [],
202
+ });
203
+ }
204
+ } catch {
205
+ /* 单封邮件获取失败不影响整体 */
206
+ }
207
+ }
208
+
209
+ return emails;
210
+ }
@@ -1,4 +1,4 @@
1
- import { EmailInfo, Email, Channel } from '../types';
1
+ import { InternalEmailInfo, Email, Channel } from '../types';
2
2
  import { normalizeEmail } from '../normalize';
3
3
 
4
4
  const CHANNEL: Channel = 'temp-mail-io';
@@ -59,7 +59,7 @@ async function getApiHeaders(): Promise<Record<string, string>> {
59
59
  * API: POST /api/v3/email/new
60
60
  * 返回: { email, token }
61
61
  */
62
- export async function generateEmail(): Promise<EmailInfo> {
62
+ export async function generateEmail(): Promise<InternalEmailInfo> {
63
63
  const headers = await getApiHeaders();
64
64
  const response = await fetch(`${BASE_URL}/email/new`, {
65
65
  method: 'POST',
@@ -1,4 +1,4 @@
1
- import { EmailInfo, Email, Channel } from '../types';
1
+ import { InternalEmailInfo, Email, Channel } from '../types';
2
2
  import { normalizeEmail } from '../normalize';
3
3
 
4
4
  const CHANNEL: Channel = 'tempmail-la';
@@ -30,7 +30,7 @@ const DEFAULT_HEADERS: Record<string, string> = {
30
30
  * API: POST /api/mail/create
31
31
  * 返回: { code: 0, data: { mailId, address, type, startAt, endAt } }
32
32
  */
33
- export async function generateEmail(): Promise<EmailInfo> {
33
+ export async function generateEmail(): Promise<InternalEmailInfo> {
34
34
  const response = await fetch(`${BASE_URL}/mail/create`, {
35
35
  method: 'POST',
36
36
  headers: DEFAULT_HEADERS,
@@ -1,4 +1,4 @@
1
- import { EmailInfo, Email, Channel } from '../types';
1
+ import { InternalEmailInfo, Email, Channel } from '../types';
2
2
  import { normalizeEmail } from '../normalize';
3
3
 
4
4
  const CHANNEL: Channel = 'tempmail-lol';
@@ -14,7 +14,7 @@ const DEFAULT_HEADERS = {
14
14
  'DNT': '1',
15
15
  };
16
16
 
17
- export async function generateEmail(domain: string | null = null): Promise<EmailInfo> {
17
+ export async function generateEmail(domain: string | null = null): Promise<InternalEmailInfo> {
18
18
  const response = await fetch(`${BASE_URL}/inbox/create`, {
19
19
  method: 'POST',
20
20
  headers: DEFAULT_HEADERS,
@@ -1,4 +1,4 @@
1
- import { EmailInfo, Email, Channel } from '../types';
1
+ import { InternalEmailInfo, Email, Channel } from '../types';
2
2
  import { normalizeEmail } from '../normalize';
3
3
 
4
4
  const CHANNEL: Channel = 'tempmail';
@@ -14,7 +14,7 @@ const DEFAULT_HEADERS = {
14
14
  'DNT': '1',
15
15
  };
16
16
 
17
- export async function generateEmail(duration: number = 30): Promise<EmailInfo> {
17
+ export async function generateEmail(duration: number = 30): Promise<InternalEmailInfo> {
18
18
  const response = await fetch(`${BASE_URL}/generate`, {
19
19
  method: 'POST',
20
20
  headers: DEFAULT_HEADERS,
package/src/retry.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { logger } from './logger';
7
+ import { getConfig } from './config';
7
8
 
8
9
  /**
9
10
  * 重试配置选项
@@ -52,6 +53,11 @@ function defaultShouldRetry(error: any): boolean {
52
53
  return true;
53
54
  }
54
55
 
56
+ /* HTTP 429 限流 → 重试 */
57
+ if (message.includes('429') || message.includes('too many requests') || message.includes('rate limit')) {
58
+ return true;
59
+ }
60
+
55
61
  /* HTTP 4xx/5xx 错误 → 重试 */
56
62
  const statusMatch = message.match(/:\s*(\d{3})/);
57
63
  if (statusMatch) {
@@ -124,20 +130,25 @@ export async function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions)
124
130
  export async function fetchWithTimeout(
125
131
  url: string,
126
132
  init?: RequestInit,
127
- timeoutMs: number = DEFAULT_RETRY_OPTIONS.timeout,
133
+ timeoutMs?: number,
128
134
  ): Promise<Response> {
135
+ const config = getConfig();
136
+ const effectiveTimeout = timeoutMs ?? config.timeout ?? DEFAULT_RETRY_OPTIONS.timeout;
129
137
  const controller = new AbortController();
130
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
138
+ const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
139
+
140
+ /* 使用自定义 fetch 或原生 fetch */
141
+ const fetchFn = config.customFetch || fetch;
131
142
 
132
143
  try {
133
- const response = await fetch(url, {
144
+ const response = await fetchFn(url, {
134
145
  ...init,
135
146
  signal: controller.signal,
136
147
  });
137
148
  return response;
138
149
  } catch (error: any) {
139
150
  if (error.name === 'AbortError') {
140
- throw new Error(`Request timeout after ${timeoutMs}ms: ${url}`);
151
+ throw new Error(`Request timeout after ${effectiveTimeout}ms: ${url}`);
141
152
  }
142
153
  throw error;
143
154
  } finally {
package/src/types.ts CHANGED
@@ -2,25 +2,33 @@
2
2
  * 支持的临时邮箱渠道标识
3
3
  * 每个渠道对应一个第三方临时邮箱服务商
4
4
  */
5
- export type Channel = 'tempmail' | 'linshi-email' | 'tempmail-lol' | 'chatgpt-org-uk' | 'tempmail-la' | 'temp-mail-io' | 'awamail' | 'mail-tm' | 'dropmail';
5
+ export type Channel = 'tempmail' | 'linshi-email' | 'tempmail-lol' | 'chatgpt-org-uk' | 'tempmail-la' | 'temp-mail-io' | 'awamail' | 'mail-tm' | 'dropmail' | 'guerrillamail' | 'maildrop';
6
6
 
7
7
  /**
8
8
  * 创建临时邮箱后返回的邮箱信息
9
- * 包含邮箱地址、认证令牌和生命周期信息
9
+ * Token 等认证信息由 SDK 内部维护,不对外暴露
10
10
  */
11
11
  export interface EmailInfo {
12
12
  /** 创建该邮箱所使用的渠道 */
13
13
  channel: Channel;
14
14
  /** 临时邮箱地址 */
15
15
  email: string;
16
- /** 认证令牌,部分渠道在获取邮件时需要此令牌 */
17
- token?: string;
18
16
  /** 邮箱过期时间(ISO 8601 字符串或 Unix 时间戳) */
19
17
  expiresAt?: string | number;
20
18
  /** 邮箱创建时间(ISO 8601 字符串) */
21
19
  createdAt?: string;
22
20
  }
23
21
 
22
+ /**
23
+ * SDK 内部使用的邮箱信息,包含 token 等认证数据
24
+ * 不对外导出,用户无法访问
25
+ * @internal
26
+ */
27
+ export interface InternalEmailInfo extends EmailInfo {
28
+ /** 认证令牌,由 SDK 内部维护 */
29
+ token?: string;
30
+ }
31
+
24
32
  /**
25
33
  * 标准化邮件附件
26
34
  * 不同渠道的附件字段名不同,SDK 统一归一化为此结构
@@ -125,26 +133,18 @@ export interface GenerateEmailOptions {
125
133
 
126
134
  /**
127
135
  * 获取邮件列表的选项
136
+ * Channel/Email/Token 等由 SDK 从 EmailInfo 中自动获取,用户无需手动传递
128
137
  *
129
138
  * @example
130
139
  * ```ts
131
- * const result = await getEmails({
132
- * channel: emailInfo.channel,
133
- * email: emailInfo.email,
134
- * token: emailInfo.token,
135
- * });
140
+ * const info = await generateEmail({ channel: 'mail-tm' });
141
+ * const result = await getEmails(info);
136
142
  * if (result.success && result.emails.length > 0) {
137
143
  * console.log('收到邮件:', result.emails);
138
144
  * }
139
145
  * ```
140
146
  */
141
147
  export interface GetEmailsOptions {
142
- /** 渠道标识,必填 */
143
- channel: Channel;
144
- /** 邮箱地址,必填 */
145
- email: string;
146
- /** 认证令牌 */
147
- token?: string;
148
148
  /** 重试配置,不传则使用默认值(最多重试 2 次) */
149
149
  retry?: RetryConfig;
150
150
  }