import type { APIRoute } from "astro"; export const POST: APIRoute = async ({ request }) => { try { console.log("Email creation request received"); const requestBody = await request.json(); console.log( "Request body:", JSON.stringify({ userId: requestBody.userId, name: requestBody.name, email: requestBody.email, passwordProvided: !!requestBody.password, }), ); const { userId, name, email, password } = requestBody; if (!userId || !name || !email) { console.log("Missing required parameters"); return new Response( JSON.stringify({ success: false, message: "Missing required parameters", }), { status: 400, headers: { "Content-Type": "application/json", }, }, ); } // Extract username from email (everything before the @ symbol) const emailUsername = email.split("@")[0].toLowerCase(); console.log(`Email username extracted: ${emailUsername}`); // Remove any special characters that might cause issues const cleanUsername = emailUsername.replace(/[^a-z0-9]/g, ""); console.log(`Cleaned username: ${cleanUsername}`); // Use provided password or generate a secure random one if not provided const newPassword = password || generateSecurePassword(); console.log(`Using ${password ? "user-provided" : "generated"} password`); // MXRoute DirectAdmin API credentials from environment variables const loginKey = import.meta.env.MXROUTE_LOGIN_KEY; const serverLogin = import.meta.env.MXROUTE_SERVER_LOGIN; const serverUrl = import.meta.env.MXROUTE_SERVER_URL; const emailQuota = import.meta.env.MXROUTE_EMAIL_QUOTA; const emailOutboundLimit = import.meta.env.MXROUTE_EMAIL_OUTBOUND_LIMIT; const emailDomain = import.meta.env.MXROUTE_EMAIL_DOMAIN; console.log(`Environment variables: loginKey: ${loginKey ? "Set" : "Not set"} serverLogin: ${serverLogin ? "Set" : "Not set"} serverUrl: ${serverUrl ? "Set" : "Not set"} emailQuota: ${emailQuota || "Not set"} emailOutboundLimit: ${emailOutboundLimit || "Not set"} emailDomain: ${emailDomain || "Not set"} `); if (!loginKey || !serverLogin || !serverUrl || !emailDomain) { throw new Error("Missing MXRoute configuration"); } // DirectAdmin API endpoint for creating email accounts let baseUrl = serverUrl; // If the URL contains a specific command, extract just the base URL if (baseUrl.includes("/CMD_")) { baseUrl = baseUrl.split("/CMD_")[0]; } // Make sure there's no trailing slash baseUrl = baseUrl.replace(/\/$/, ""); // Construct the email POP API URL const emailApiUrl = `${baseUrl}/CMD_API_EMAIL_POP`; console.log(`Creating email account: ${cleanUsername}@${emailDomain}`); console.log(`DirectAdmin API URL: ${emailApiUrl}`); // Create the email account via DirectAdmin API // According to DirectAdmin legacy API docs: // https://docs.directadmin.com/developer/api/legacy-api.html const formData = new URLSearchParams(); formData.append("action", "create"); formData.append("domain", emailDomain); formData.append("user", cleanUsername); // DirectAdmin uses 'user' for POP accounts formData.append("passwd", newPassword); formData.append("passwd2", newPassword); formData.append("quota", emailQuota || "200"); formData.append("limit", emailOutboundLimit || "9600"); // Log the form data being sent (without showing the actual password) console.log("Form data:"); console.log(` action: create`); console.log(` domain: ${emailDomain}`); console.log(` user: ${cleanUsername}`); console.log(` passwd: ********`); console.log(` passwd2: ********`); console.log(` quota: ${emailQuota || "200"}`); console.log(` limit: ${emailOutboundLimit || "9600"}`); console.log("Sending request to DirectAdmin API..."); const response = await fetch(emailApiUrl, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", Authorization: `Basic ${Buffer.from(`${serverLogin}:${loginKey}`).toString("base64")}`, }, body: formData, }); const responseText = await response.text(); console.log(`DirectAdmin response status: ${response.status}`); console.log(`DirectAdmin response: ${responseText}`); // DirectAdmin API returns "error=1" in the response text for errors if (responseText.includes("error=1") || !response.ok) { console.error("Error creating email account:", responseText); // Parse the error details if possible let errorMessage = "Failed to create email account"; try { const errorParams = new URLSearchParams(responseText); if (errorParams.has("text")) { errorMessage = decodeURIComponent(errorParams.get("text") || ""); } if (errorParams.has("details")) { const details = decodeURIComponent(errorParams.get("details") || ""); errorMessage += `: ${details.replace(/
/g, " ")}`; } } catch (e) { console.error("Error parsing DirectAdmin error response:", e); } // If the error is because the email already exists if (responseText.includes("already exists")) { return new Response( JSON.stringify({ success: false, message: `Email address ${cleanUsername}@${emailDomain} already exists. Please contact the webmaster for assistance.`, }), { status: 409, headers: { "Content-Type": "application/json", }, }, ); } throw new Error(errorMessage); } console.log("Email account created successfully"); // Only send notification email if we generated a random password if (!password) { console.log("Sending credentials email to user"); await sendCredentialsEmail( email, `${cleanUsername}@${emailDomain}`, newPassword, ); } console.log("Sending notification to webmaster"); await sendWebmasterNotification( userId, name, email, `${cleanUsername}@${emailDomain}`, ); return new Response( JSON.stringify({ success: true, data: { ieeeEmail: `${cleanUsername}@${emailDomain}`, message: password ? "Email account created successfully with your chosen password." : "Email account created successfully. Check your email for login details.", }, }), { status: 200, headers: { "Content-Type": "application/json", }, }, ); } catch (error) { console.error("Error in create-ieee-email:", error); return new Response( JSON.stringify({ success: false, message: error instanceof Error ? error.message : "An error occurred", }), { status: 500, headers: { "Content-Type": "application/json", }, }, ); } }; // Generate a secure random password function generateSecurePassword(length = 16) { const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+"; let password = ""; // Ensure at least one character from each category password += charset.substring(0, 26).charAt(Math.floor(Math.random() * 26)); // lowercase password += charset.substring(26, 52).charAt(Math.floor(Math.random() * 26)); // uppercase password += charset.substring(52, 62).charAt(Math.floor(Math.random() * 10)); // number password += charset .substring(62) .charAt(Math.floor(Math.random() * (charset.length - 62))); // special // Fill the rest randomly for (let i = 4; i < length; i++) { password += charset.charAt(Math.floor(Math.random() * charset.length)); } // Shuffle the password return password .split("") .sort(() => 0.5 - Math.random()) .join(""); } // Send email with credentials to the user async function sendCredentialsEmail( userEmail: string, ieeeEmail: string, password: string, ) { // In a real implementation, you would use an email service like SendGrid, Mailgun, etc. // For now, we'll just log the email that would be sent console.log(` To: ${userEmail} Subject: Your IEEE UCSD Email Account Hello, Your IEEE UCSD email account has been created: Email address: ${ieeeEmail} Password: ${password} You can access your email through: - Webmail: https://heracles.mxrouting.net:2096/ - IMAP/SMTP settings can be found at: https://mxroute.com/setup/ ===== Setting Up Your IEEE Email in Gmail ===== --- First Step: Set Up Sending From Your IEEE Email --- 1. Go to settings (gear icon) → Accounts and Import 2. In the section that says "Send mail as:", select "Reply from the same address the message was sent to" 3. In that same section, select "Add another email address" 4. For the Name, put your actual name or department name (e.g. IEEEUCSD Webmaster) 5. For the Email address, put ${ieeeEmail} 6. Make sure the "Treat as an alias" button is selected. Go to the next step 7. For the SMTP Server, put mail.ieeeucsd.org 8. For the username, put in your FULL ieeeucsd email address (${ieeeEmail}) 9. For the password, put in the email's password (provided above) 10. For the port, put in 587 11. Make sure you select "Secured connection with TLS" 12. Go back to mail.ieeeucsd.org and verify the email that Google has sent you --- Second Step: Set Up Receiving Your IEEE Email --- 1. Go to settings (gear icon) → Accounts and Import 2. In the section that says "Check mail from other accounts:", select "Add a mail account" 3. Put in ${ieeeEmail} and hit next 4. Make sure "Import emails from my other account (POP3)" is selected, then hit next 5. For the username, put in ${ieeeEmail} 6. For the password, put in your password (provided above) 7. For the POP Server, put in mail.ieeeucsd.org 8. For the Port, put in 995 9. Select "Leave a copy of retrieved message on the server" 10. Select "Always use a secure connection (SSL) when retrieving mail" 11. Select "Label incoming messages" 12. Then hit "Add Account" Please change your password after your first login. If you have any questions, please contact webmaster@ieeeucsd.org. Best regards, IEEE UCSD Web Team `); // In a production environment, replace with actual email sending code return true; } // Send notification to webmaster async function sendWebmasterNotification( userId: string, name: string, email: string, ieeeEmail: string, ) { // In a real implementation, you would use an email service console.log(` To: webmaster@ieeeucsd.org Subject: New IEEE Email Account Created A new IEEE email account has been created: User ID: ${userId} Name: ${name} Personal Email: ${email} IEEE Email: ${ieeeEmail} This is an automated notification. `); // In a production environment, replace with actual email sending code return true; }