Rackspace Email API Workflows
This guide provides detailed workflows for all Rackspace Email integration operations, including email creation, availability checking, and password management.
Authentication Workflow
All Rackspace API requests require authentication via the X-Api-Signature header.
Signature Generation Process
const crypto = require('crypto');
function generateSignature(apiKey, secretKey, userAgent = 'MyNATCA Platform') {
// 1. Get current Unix timestamp (seconds)
const timestamp = Math.floor(Date.now() / 1000).toString();
// 2. Concatenate components
const dataToSign = apiKey + userAgent + timestamp + secretKey;
// 3. Generate SHA1 hash
const signature = crypto
.createHash('sha1')
.update(dataToSign)
.digest('hex');
// 4. Format header value
const headerValue = `${apiKey}:${timestamp}:${signature}`;
return {
timestamp,
signature,
headerValue
};
}
// Usage
const auth = generateSignature(
process.env.RACKSPACE_API_KEY,
process.env.RACKSPACE_SECRET_KEY
);
const headers = {
'X-Api-Signature': auth.headerValue,
'User-Agent': 'MyNATCA Platform',
'Content-Type': 'application/json'
};Authentication Headers
Every Rackspace API request includes:
X-Api-Signature: apiKey:timestamp:sha1Hash
User-Agent: MyNATCA Platform
Content-Type: application/jsonEmail Availability Check Workflow
Checks if proposed email formats are available before creation.
Flow Diagram
User Request
↓
Platform API: Validate Session
↓
Platform API: Get Member Info
↓
Platform API: Generate Email Formats
↓
Rackspace API: Check Format 1 (jdoss@natca.net)
↓
Rackspace API: Check Format 2 (jason.doss@natca.net)
↓
Platform API: Return Available Formats
↓
User ResponseAPI Endpoint
POST /api/rackspace/check-availability
Authorization: Session Cookie (Auth0)
Content-Type: application/jsonRequest
{
"memberNumber": "12345"
}Implementation
// 1. Validate Auth0 session
if (!req.session || !req.session.user) {
return res.status(401).json({ error: 'Authentication required' });
}
// 2. Fetch member data from MySQL
const [members] = await pool.query(
'SELECT membernumber, firstname, lastname, membertypeid, status FROM members WHERE membernumber = ?',
[memberNumber]
);
if (members.length === 0) {
return res.status(404).json({ error: 'Member not found' });
}
const member = members[0];
// 3. Validate member eligibility
if (member.membertypeid !== 6) {
return res.status(400).json({
error: 'Only NATCA members are eligible for @natca.net emails'
});
}
if (!['Active', 'Retired'].includes(member.status)) {
return res.status(400).json({
error: 'Only Active or Retired members can receive @natca.net emails'
});
}
// 4. Check for existing NATCA email
const [existing] = await pool.query(
"SELECT emailaddress FROM emailinformation WHERE membernumber = ? AND emailaddress LIKE '%@natca.net'",
[memberNumber]
);
if (existing.length > 0) {
return res.status(400).json({
error: 'Member already has a @natca.net email',
existingEmail: existing[0].emailaddress
});
}
// 5. Generate email format options
const formats = [
`${member.firstname.charAt(0).toLowerCase()}${member.lastname.toLowerCase()}@natca.net`,
`${member.firstname.toLowerCase()}.${member.lastname.toLowerCase()}@natca.net`
];
// 6. Check availability with Rackspace
const availableFormats = [];
for (const format of formats) {
const exists = await rackspaceClient.checkMailboxExists(format);
if (!exists) {
availableFormats.push(format);
}
}
// 7. Return results
res.json({
memberNumber: member.membernumber,
firstName: member.firstname,
lastName: member.lastname,
availableFormats
});Response
{
"memberNumber": "12345",
"firstName": "Jason",
"lastName": "Doss",
"availableFormats": [
"jdoss@natca.net",
"jason.doss@natca.net"
]
}Error Responses
Member Not Eligible
{
"error": "Only NATCA members are eligible for @natca.net emails"
}Already Has Email
{
"error": "Member already has a @natca.net email",
"existingEmail": "jdoss@natca.net"
}No Formats Available
{
"memberNumber": "12345",
"firstName": "Jason",
"lastName": "Doss",
"availableFormats": []
}Email Creation Workflow
Creates a new @natca.net email account for an eligible member.
Flow Diagram
User Request (selects email format)
↓
Platform API: Validate Session
↓
Platform API: Validate Member Eligibility
↓
Platform API: Check No Existing NATCA Email
↓
Platform API: Generate Secure Password
↓
Rackspace API: Create Mailbox
↓
Platform API: Add Email to Member Profile (MySQL)
↓
Platform API: Return Credentials (password shown once)
↓
User Response (save password)API Endpoint
POST /api/rackspace/create-email
Authorization: Session Cookie (Auth0)
Content-Type: application/jsonRequest
{
"memberNumber": "12345",
"emailFormat": "jdoss@natca.net"
}Implementation
// 1. Validate session and member eligibility (same as availability check)
// 2. Validate email format
if (!emailFormat.endsWith('@natca.net')) {
return res.status(400).json({ error: 'Invalid email format' });
}
// 3. Verify email doesn't already exist
const exists = await rackspaceClient.checkMailboxExists(emailFormat);
if (exists) {
return res.status(400).json({
error: 'Email address already exists',
email: emailFormat
});
}
// 4. Generate secure password
const password = rackspaceClient.generatePassword();
// Returns: 16-char password with uppercase, lowercase, numbers, special chars
// 5. Create mailbox in Rackspace
await rackspaceClient.createMailbox({
emailAddress: emailFormat,
password: password,
displayName: `${member.firstname} ${member.lastname}`,
firstName: member.firstname,
lastName: member.lastname
});
// 6. Add email to member profile in MySQL
await pool.query(
'INSERT INTO emailinformation (membernumber, emailaddress, emailtypeid, isactive) VALUES (?, ?, ?, ?)',
[memberNumber, emailFormat, 3, 1] // emailtypeid=3 for organizational email
);
// 7. Log successful creation
logger.info('NATCA email created', {
memberNumber,
email: emailFormat,
service: 'rackspace'
});
// 8. Return credentials (password shown once)
res.json({
success: true,
email: emailFormat,
password: password,
message: 'Email created successfully. Save your password - it will not be shown again.'
});Response
{
"success": true,
"email": "jdoss@natca.net",
"password": "Xy9#mK2@pL5qR8zA",
"message": "Email created successfully. Save your password - it will not be shown again."
}Rackspace API Call
POST https://api.emailsrvr.com/v1/customers/{customerId}/domains/natca.net/rs/mailboxes
X-Api-Signature: apiKey:timestamp:signature
User-Agent: MyNATCA Platform
Content-Type: application/json
{
"name": "jdoss",
"password": "Xy9#mK2@pL5qR8zA",
"displayName": "Jason Doss",
"firstName": "Jason",
"lastName": "Doss",
"enabled": true
}Error Responses
Email Already Exists
{
"error": "Email address already exists",
"email": "jdoss@natca.net"
}Rackspace API Error
{
"error": "Failed to create email account",
"message": "Rackspace API error: Mailbox quota exceeded"
}Database Error
{
"error": "Failed to update member profile",
"message": "Unable to save email to database"
}Password Reset Workflow
Resets the password for an existing @natca.net email account.
Flow Diagram
User Request (existing email)
↓
Platform API: Validate Session
↓
Platform API: Verify Member Owns Email
↓
Platform API: Generate New Secure Password
↓
Rackspace API: Reset Mailbox Password
↓
Platform API: Return New Password (shown once)
↓
User Response (save new password)API Endpoint
POST /api/rackspace/reset-password
Authorization: Session Cookie (Auth0)
Content-Type: application/jsonRequest
{
"memberNumber": "12345",
"email": "jdoss@natca.net"
}Implementation
// 1. Validate session
if (!req.session || !req.session.user) {
return res.status(401).json({ error: 'Authentication required' });
}
// 2. Validate email belongs to member
const [emailRecords] = await pool.query(
'SELECT emailaddress FROM emailinformation WHERE membernumber = ? AND emailaddress = ?',
[memberNumber, email]
);
if (emailRecords.length === 0) {
return res.status(404).json({
error: 'Email not found or does not belong to this member'
});
}
// 3. Verify email exists in Rackspace
const exists = await rackspaceClient.checkMailboxExists(email);
if (!exists) {
return res.status(404).json({
error: 'Email account not found in Rackspace',
email
});
}
// 4. Generate new secure password
const newPassword = rackspaceClient.generatePassword();
// 5. Reset password in Rackspace
await rackspaceClient.resetPassword(email, newPassword);
// 6. Log password reset
logger.info('NATCA email password reset', {
memberNumber,
email,
service: 'rackspace'
});
// 7. Return new password (shown once)
res.json({
success: true,
email,
newPassword,
message: 'Password reset successfully. Save your new password - it will not be shown again.'
});Response
{
"success": true,
"email": "jdoss@natca.net",
"newPassword": "Bz7!nQ4@wP9xM2yH",
"message": "Password reset successfully. Save your new password - it will not be shown again."
}Rackspace API Call
PUT https://api.emailsrvr.com/v1/customers/{customerId}/domains/natca.net/rs/mailboxes/jdoss
X-Api-Signature: apiKey:timestamp:signature
User-Agent: MyNATCA Platform
Content-Type: application/json
{
"password": "Bz7!nQ4@wP9xM2yH"
}Error Responses
Email Not Found
{
"error": "Email not found or does not belong to this member"
}Rackspace API Error
{
"error": "Failed to reset password",
"message": "Rackspace API error: Mailbox not found"
}Password Generation
Generates secure passwords meeting Rackspace requirements.
Requirements
- Minimum length: 8 characters
- Character types: At least 3 of 4 types:
- Uppercase letters (A-Z)
- Lowercase letters (a-z)
- Numbers (0-9)
- Special characters (!@#$%^&*)
Implementation
generatePassword(length = 16) {
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const lowercase = 'abcdefghijklmnopqrstuvwxyz';
const numbers = '0123456789';
const special = '!@#$%^&*';
// Ensure at least one of each type
let password = '';
password += uppercase[Math.floor(Math.random() * uppercase.length)];
password += lowercase[Math.floor(Math.random() * lowercase.length)];
password += numbers[Math.floor(Math.random() * numbers.length)];
password += special[Math.floor(Math.random() * special.length)];
// Fill remaining length with random characters from all sets
const allChars = uppercase + lowercase + numbers + special;
for (let i = password.length; i < length; i++) {
password += allChars[Math.floor(Math.random() * allChars.length)];
}
// Shuffle password to randomize character positions
return password.split('').sort(() => Math.random() - 0.5).join('');
}Example Output
const password = generatePassword();
// Returns: "Xy9#mK2@pL5qR8zA" (16 characters)
// Breakdown:
// - 4 uppercase: X, K, R, A
// - 5 lowercase: y, m, p, q, z
// - 4 numbers: 9, 2, 5, 8
// - 3 special: #, @, @Complete Integration Example
Member Hub Frontend
// Member Hub: Check availability
async function checkEmailAvailability(memberNumber) {
const response = await fetch('/api/rackspace/check-availability', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ memberNumber })
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Failed to check availability');
}
return data;
}
// Member Hub: Create email
async function createEmail(memberNumber, emailFormat) {
const response = await fetch('/api/rackspace/create-email', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ memberNumber, emailFormat })
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Failed to create email');
}
// Display password to user (one-time display)
alert(`Your email has been created!\n\nEmail: ${data.email}\nPassword: ${data.password}\n\nSave this password - it will not be shown again!`);
return data;
}
// Member Hub: Reset password
async function resetPassword(memberNumber, email) {
const response = await fetch('/api/rackspace/reset-password', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ memberNumber, email })
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Failed to reset password');
}
// Display new password to user (one-time display)
alert(`Password reset successful!\n\nEmail: ${data.email}\nNew Password: ${data.newPassword}\n\nSave this password - it will not be shown again!`);
return data;
}Error Handling
try {
// Check availability
const availability = await checkEmailAvailability('12345');
if (availability.availableFormats.length === 0) {
showError('No email formats available. Please contact support.');
return;
}
// User selects format
const selectedFormat = availability.availableFormats[0];
// Create email
const result = await createEmail('12345', selectedFormat);
showSuccess(`Email created: ${result.email}`);
} catch (error) {
console.error('Email creation error:', error);
showError(error.message);
}Rate Limiting and Retry Logic
Rackspace API Rate Limits
Rackspace Email API typically allows:
- Rate limit: 60 requests per minute per API key
- Concurrent requests: Maximum 10 concurrent requests
Retry Implementation
async makeRequest(url, options, retries = 3) {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const response = await fetch(url, options);
// Success
if (response.ok) {
return response;
}
// Rate limited - wait and retry
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
logger.warn('Rate limited, retrying', { attempt, retryAfter });
await this.sleep(retryAfter * 1000);
continue;
}
// Other errors - throw
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
} catch (error) {
if (attempt === retries) {
throw error;
}
// Exponential backoff
const delay = Math.pow(2, attempt) * 1000;
logger.warn('Request failed, retrying', { attempt, delay });
await this.sleep(delay);
}
}
}Related Documentation
These workflows ensure reliable and secure email account management for NATCA members through the Rackspace Email integration.