一键导入
wraps-sms
TypeScript SDK for AWS End User Messaging (Pinpoint SMS) with opt-out management, batch sending, and E.164 validation.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
TypeScript SDK for AWS End User Messaging (Pinpoint SMS) with opt-out management, batch sending, and E.164 validation.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
CLI that deploys SES, DynamoDB, Lambda, and IAM resources to your AWS account with automatic DKIM, SPF, DMARC configuration.
Email deliverability, warming, compliance, and operational guidelines for AWS Simple Email Service.
Best practices for email content that avoids spam filters. Apply these rules when writing email copy, building templates, or debugging spam placement issues.
Interactive SES deliverability troubleshooting. Diagnoses bounces, spam placement, send failures, account health, and complaint issues with targeted AWS CLI commands and ordered remediation steps.
TypeScript SDK for AWS SES with automatic credential resolution, React.email support, and template management.
Get started with Wraps email infrastructure. Guides through deploying infrastructure, verifying a domain, installing the SDK, and sending the first email. Adapts to project framework and hosting provider.
| name | wraps-sms |
| description | TypeScript SDK for AWS End User Messaging (Pinpoint SMS) with opt-out management, batch sending, and E.164 validation. |
TypeScript SDK for AWS End User Messaging (Pinpoint SMS) with opt-out management, batch sending, and E.164 validation. Calls your AWS account directly — no proxy, no markup.
npm install @wraps.dev/sms
# or
pnpm add @wraps.dev/sms
import { WrapsSMS } from '@wraps.dev/sms';
const sms = new WrapsSMS();
const result = await sms.send({
to: '+14155551234',
message: 'Your verification code is 123456',
});
console.log('Sent:', result.messageId);
// Uses AWS credential chain (env vars, IAM role, ~/.aws/credentials)
const sms = new WrapsSMS();
const sms = new WrapsSMS({
region: 'us-west-2', // defaults to us-east-1
});
const sms = new WrapsSMS({
region: 'us-east-1',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
});
// For Vercel, EKS, GitHub Actions with OIDC federation
const sms = new WrapsSMS({
region: 'us-east-1',
roleArn: 'arn:aws:iam::123456789012:role/WrapsSMSRole',
roleSessionName: 'my-app-session', // optional
});
import { fromWebToken } from '@aws-sdk/credential-providers';
const credentials = fromWebToken({
roleArn: process.env.AWS_ROLE_ARN!,
webIdentityToken: async () => process.env.VERCEL_OIDC_TOKEN!,
});
const sms = new WrapsSMS({
region: 'us-east-1',
credentials,
});
const result = await sms.send({
to: '+14155551234', // E.164 format required
message: 'Hello from Wraps!',
});
console.log('Message ID:', result.messageId);
console.log('Segments:', result.segments);
console.log('Status:', result.status);
// OTP, alerts, notifications (higher priority, opt-out not required)
await sms.send({
to: '+14155551234',
message: 'Your code is 123456',
messageType: 'TRANSACTIONAL', // default
});
// Marketing messages (requires opt-in, subject to quiet hours)
await sms.send({
to: '+14155551234',
message: 'Sale! 20% off today only!',
messageType: 'PROMOTIONAL',
});
// Use a specific origination number from your account
await sms.send({
to: '+14155551234',
message: 'Hello!',
from: '+18005551234', // Your registered number
});
await sms.send({
to: '+14155551234',
message: 'Your order has shipped!',
context: {
orderId: 'order_123',
userId: 'user_456',
type: 'shipping_notification',
},
});
// Fail if message would cost more than specified amount
await sms.send({
to: '+14155551234',
message: 'Hello!',
maxPrice: '0.05', // USD per segment
});
// Message expires if not delivered within TTL
await sms.send({
to: '+14155551234',
message: 'Your OTP is 123456',
ttl: 300, // 5 minutes in seconds
});
const result = await sms.send({
to: '+14155551234',
message: 'Test message',
dryRun: true,
});
console.log('Would use', result.segments, 'segment(s)');
// No message is actually sent
const result = await sms.sendBatch({
messages: [
{ to: '+14155551234', message: 'Hello Alice!' },
{ to: '+14155555678', message: 'Hello Bob!' },
{ to: '+14155559012', message: 'Hello Carol!' },
],
messageType: 'TRANSACTIONAL',
});
console.log(`Total: ${result.total}`);
console.log(`Queued: ${result.queued}`);
console.log(`Failed: ${result.failed}`);
// Check individual results
result.results.forEach((r) => {
if (r.status === 'QUEUED') {
console.log(`${r.to}: ${r.messageId}`);
} else {
console.log(`${r.to}: FAILED - ${r.error}`);
}
});
const numbers = await sms.numbers.list();
numbers.forEach((n) => {
console.log(`${n.phoneNumber} (${n.numberType})`);
console.log(` Message type: ${n.messageType}`);
console.log(` Two-way enabled: ${n.twoWayEnabled}`);
console.log(` Country: ${n.isoCountryCode}`);
});
const number = await sms.numbers.get('phone-number-id-123');
if (number) {
console.log(`Phone: ${number.phoneNumber}`);
console.log(`Type: ${number.numberType}`);
}
TCPA compliance requires honoring opt-out requests.
const isOptedOut = await sms.optOuts.check('+14155551234');
if (isOptedOut) {
console.log('User has opted out, do not send');
} else {
await sms.send({
to: '+14155551234',
message: 'Hello!',
});
}
const optOuts = await sms.optOuts.list();
optOuts.forEach((entry) => {
console.log(`${entry.phoneNumber} opted out at ${entry.optedOutAt}`);
});
// User requested to stop receiving messages
await sms.optOuts.add('+14155551234');
// User re-subscribed (must have explicit consent)
await sms.optOuts.remove('+14155551234');
import { WrapsSMS, SMSError, ValidationError, OptedOutError } from '@wraps.dev/sms';
try {
await sms.send({
to: '+14155551234',
message: 'Hello!',
});
} catch (error) {
if (error instanceof ValidationError) {
// Invalid parameters (e.g., invalid phone number format)
console.error('Validation error:', error.message);
} else if (error instanceof OptedOutError) {
// Recipient has opted out
console.error('User opted out:', error.phoneNumber);
} else if (error instanceof SMSError) {
// AWS SMS service error
console.error('SMS error:', error.message);
console.error('Error code:', error.code);
console.error('Request ID:', error.requestId);
console.error('Is throttled:', error.isThrottled);
} else {
throw error;
}
}
import { validatePhoneNumber } from '@wraps.dev/sms';
const isValid = validatePhoneNumber('+14155551234'); // true
const isInvalid = validatePhoneNumber('415-555-1234'); // false (not E.164)
import { sanitizePhoneNumber } from '@wraps.dev/sms';
const clean = sanitizePhoneNumber('(415) 555-1234', 'US');
// Returns: '+14155551234'
import { calculateSegments } from '@wraps.dev/sms';
// GSM-7 encoding: 160 chars = 1 segment
const segments1 = calculateSegments('Hello world!'); // 1
// Unicode: 70 chars = 1 segment
const segments2 = calculateSegments('Hello! emoji here'); // may be more due to encoding
// Long message
const longMsg = 'A'.repeat(200);
const segments3 = calculateSegments(longMsg); // 2 (for GSM-7)
// When done (e.g., in serverless cleanup or app shutdown)
sms.destroy();
import type {
WrapsSMSConfig,
SendOptions,
SendResult,
BatchOptions,
BatchResult,
BatchMessage,
BatchMessageResult,
PhoneNumber,
OptOutEntry,
MessageType,
MessageStatus,
} from '@wraps.dev/sms';
import { WrapsSMS } from '@wraps.dev/sms';
class OTPService {
private sms: WrapsSMS;
constructor() {
this.sms = new WrapsSMS({
region: process.env.AWS_REGION,
});
}
async sendOTP(phoneNumber: string, code: string) {
return this.sms.send({
to: phoneNumber,
message: `Your verification code is ${code}. Valid for 10 minutes.`,
messageType: 'TRANSACTIONAL',
ttl: 600, // 10 minutes
context: {
type: 'otp',
},
});
}
}
import { WrapsSMS, OptedOutError } from '@wraps.dev/sms';
class NotificationService {
private sms: WrapsSMS;
constructor() {
this.sms = new WrapsSMS();
}
async sendNotification(phoneNumber: string, message: string) {
// Check opt-out status first
const isOptedOut = await this.sms.optOuts.check(phoneNumber);
if (isOptedOut) {
console.log(`Skipping ${phoneNumber} - opted out`);
return null;
}
try {
return await this.sms.send({
to: phoneNumber,
message,
messageType: 'TRANSACTIONAL',
});
} catch (error) {
if (error instanceof OptedOutError) {
// Race condition: user opted out between check and send
console.log(`User ${phoneNumber} opted out`);
return null;
}
throw error;
}
}
}
import { WrapsSMS } from '@wraps.dev/sms';
// Initialize outside handler for connection reuse
const sms = new WrapsSMS({
roleArn: process.env.AWS_ROLE_ARN,
});
export async function POST(request: Request) {
const { to, message } = await request.json();
const result = await sms.send({
to,
message,
messageType: 'TRANSACTIONAL',
});
return Response.json({ messageId: result.messageId });
}
Always use E.164 format:
+14155551234 (not 415-555-1234)+447911123456 (not 07911 123456)+4915112345678Messages are billed per segment: