diff --git a/.env.example b/.env.example
index 07e9081000..02d1fca941 100644
--- a/.env.example
+++ b/.env.example
@@ -85,6 +85,8 @@ SENDGRID_EMAIL=
TWILIO_SID=
TWILIO_TOKEN=
TWILIO_MESSAGING_SID=
+TWILIO_PHONE_NUMBER=
+NEXT_PUBLIC_SENDER_ID=
# This is used so we can bypass emails in auth flows for E2E testing
# Set it to "1" if you need to run E2E tests locally
diff --git a/README.md b/README.md
index b73b14fd67..79f7edb80b 100644
--- a/README.md
+++ b/README.md
@@ -419,14 +419,16 @@ following
2. Click ‘Get a Twilio phone number’
3. Copy Account SID to your .env file into the TWILIO_SID field
4. Copy Auth Token to your .env file into the TWILIO_TOKEN field
-5. Create a messaging service (Develop -> Messaging -> Services)
-6. Choose any name for the messaging service
-7. Click 'Add Senders'
-8. Choose phone number as sender type
-9. Add the listed phone number
-10. Leave all other fields as they are
-11. Complete setup and click ‘View my new Messaging Service’
-12. Copy Messaging Service SID to your .env file into the TWILIO_MESSAGING_SID field
+5. Copy your Twilio phone number to your .env file into the TWILIO_PHONE_NUMBER field
+6. Add your own sender id to the .env file into the NEXT_PUBLIC_SENDER_ID field (fallback is Cal)
+7. Create a messaging service (Develop -> Messaging -> Services)
+8. Choose any name for the messaging service
+9. Click 'Add Senders'
+10. Choose phone number as sender type
+11. Add the listed phone number
+12. Leave all other fields as they are
+13. Complete setup and click ‘View my new Messaging Service’
+14. Copy Messaging Service SID to your .env file into the TWILIO_MESSAGING_SID field
diff --git a/packages/features/ee/workflows/api/scheduleSMSReminders.ts b/packages/features/ee/workflows/api/scheduleSMSReminders.ts
index f0186cb219..ac61ba7a90 100644
--- a/packages/features/ee/workflows/api/scheduleSMSReminders.ts
+++ b/packages/features/ee/workflows/api/scheduleSMSReminders.ts
@@ -6,6 +6,7 @@ import dayjs from "@calcom/dayjs";
import { defaultHandler } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
+import { getSenderId } from "../lib/alphanumericSenderIdSupport";
import * as twilio from "../lib/reminders/smsProviders/twilioProvider";
import customTemplate, { VariablesType } from "../lib/reminders/templates/customTemplate";
import smsReminderTemplate from "../lib/reminders/templates/smsReminderTemplate";
@@ -72,6 +73,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
? reminder.booking?.attendees[0].timeZone
: reminder.booking?.user?.timeZone;
+ const senderID = getSenderId(sendTo, reminder.workflowStep.sender);
+
let message: string | null = reminder.workflowStep.reminderBody;
switch (reminder.workflowStep.template) {
case WorkflowTemplates.REMINDER:
@@ -105,12 +108,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
break;
}
if (message?.length && message?.length > 0 && sendTo) {
- const scheduledSMS = await twilio.scheduleSMS(
- sendTo,
- message,
- reminder.scheduledDate,
- reminder.workflowStep.sender || "Cal"
- );
+ const scheduledSMS = await twilio.scheduleSMS(sendTo, message, reminder.scheduledDate, senderID);
await prisma.workflowReminder.update({
where: {
diff --git a/packages/features/ee/workflows/components/AddActionDialog.tsx b/packages/features/ee/workflows/components/AddActionDialog.tsx
index c515b8e26b..b2945754db 100644
--- a/packages/features/ee/workflows/components/AddActionDialog.tsx
+++ b/packages/features/ee/workflows/components/AddActionDialog.tsx
@@ -5,6 +5,7 @@ import { Dispatch, SetStateAction, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { z } from "zod";
+import { SENDER_ID } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import {
Button,
@@ -68,7 +69,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
mode: "onSubmit",
defaultValues: {
action: WorkflowActions.EMAIL_HOST,
- sender: "Cal",
+ sender: SENDER_ID,
},
resolver: zodResolver(formSchema),
});
@@ -166,7 +167,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
diff --git a/packages/features/ee/workflows/components/WorkflowDetailsPage.tsx b/packages/features/ee/workflows/components/WorkflowDetailsPage.tsx
index b2d220f11d..6569a3242a 100644
--- a/packages/features/ee/workflows/components/WorkflowDetailsPage.tsx
+++ b/packages/features/ee/workflows/components/WorkflowDetailsPage.tsx
@@ -3,6 +3,7 @@ import { useRouter } from "next/router";
import { Dispatch, SetStateAction, useMemo, useState } from "react";
import { Controller, UseFormReturn } from "react-hook-form";
+import { SENDER_ID } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
@@ -73,7 +74,7 @@ export default function WorkflowDetailsPage(props: Props) {
emailSubject: null,
template: WorkflowTemplates.CUSTOM,
numberRequired: numberRequired || false,
- sender: sender || "Cal",
+ sender: sender || SENDER_ID,
};
steps?.push(step);
form.setValue("steps", steps);
diff --git a/packages/features/ee/workflows/components/WorkflowStepContainer.tsx b/packages/features/ee/workflows/components/WorkflowStepContainer.tsx
index 5a2e525651..e8b990e0fa 100644
--- a/packages/features/ee/workflows/components/WorkflowStepContainer.tsx
+++ b/packages/features/ee/workflows/components/WorkflowStepContainer.tsx
@@ -9,6 +9,7 @@ import { Dispatch, SetStateAction, useRef, useState } from "react";
import { Controller, UseFormReturn } from "react-hook-form";
import "react-phone-number-input/style.css";
+import { SENDER_ID } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HttpError } from "@calcom/lib/http-error";
import { trpc } from "@calcom/trpc/react";
@@ -366,7 +367,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
@@ -557,7 +558,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
emailSubject,
reminderBody,
template: step.template,
- sender: step.sender || "Cal",
+ sender: step.sender || SENDER_ID,
});
} else {
const isNumberValid =
@@ -596,6 +597,7 @@ export default function WorkflowStepContainer(props: WorkflowStepProps) {
reminderBody: reminderBody || "",
template: step.template,
sendTo: step.sendTo || "",
+ sender: step.sender || SENDER_ID,
});
setConfirmationDialogOpen(false);
}}>
diff --git a/packages/features/ee/workflows/lib/alphanumericSenderIdSupport.ts b/packages/features/ee/workflows/lib/alphanumericSenderIdSupport.ts
new file mode 100644
index 0000000000..1271577673
--- /dev/null
+++ b/packages/features/ee/workflows/lib/alphanumericSenderIdSupport.ts
@@ -0,0 +1,87 @@
+import { SENDER_ID } from "@calcom/lib/constants";
+
+export function getSenderId(phoneNumber?: string | null, sender?: string | null) {
+ const isAlphanumericSenderIdSupported = !noAlphanumericSenderIdSupport.find(
+ (code) => code === phoneNumber?.substring(0, code.length)
+ );
+
+ const senderID = isAlphanumericSenderIdSupported ? sender || SENDER_ID : "";
+
+ return senderID;
+}
+
+const noAlphanumericSenderIdSupport = [
+ "+93",
+ "+54",
+ "+374",
+ "+1",
+ "+375",
+ "+32",
+ "+229",
+ "+55",
+ "+237",
+ "+56",
+ "+86",
+ "+57",
+ "+243",
+ "+506",
+ "+53",
+ "+42",
+ "+593",
+ "+20",
+ "+503",
+ "+251",
+ "+594",
+ "+233",
+ "+224",
+ "+245",
+ "+852",
+ "+36",
+ "+91",
+ "+62",
+ "+98",
+ "+972",
+ "+225",
+ "+962",
+ "+7",
+ "+254",
+ "+965",
+ "+996",
+ "+231",
+ "+60",
+ "+52",
+ "+212",
+ "+95",
+ "+674",
+ "+977",
+ "+64",
+ "+505",
+ "+234",
+ "+968",
+ "+507",
+ "+595",
+ "+51",
+ "+63",
+ "+974",
+ "+7",
+ "+250",
+ "+966",
+ "+27",
+ "+82",
+ "+211",
+ "+94",
+ "+249",
+ "+268",
+ "+963",
+ "+886",
+ "+255",
+ "+66",
+ "+216",
+ "+90",
+ "+256",
+ "+971",
+ "+598",
+ "+58",
+ "+84",
+ "+260",
+];
diff --git a/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts b/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts
index 5990830bb8..e104b41c88 100644
--- a/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts
+++ b/packages/features/ee/workflows/lib/reminders/reminderScheduler.ts
@@ -6,6 +6,7 @@ import {
WorkflowTriggerEvents,
} from "@prisma/client";
+import { SENDER_ID } from "@calcom/lib/constants";
import type { CalendarEvent } from "@calcom/types/Calendar";
import { scheduleEmailReminder } from "./emailReminderManager";
@@ -51,7 +52,7 @@ export const scheduleWorkflowReminders = async (
step.reminderBody || "",
step.id,
step.template,
- step.sender || "Cal"
+ step.sender || SENDER_ID
);
} else if (
step.action === WorkflowActions.EMAIL_ATTENDEE ||
@@ -120,7 +121,7 @@ export const sendCancelledReminders = async (
step.reminderBody || "",
step.id,
step.template,
- step.sender || "Cal"
+ step.sender || SENDER_ID
);
} else if (
step.action === WorkflowActions.EMAIL_ATTENDEE ||
diff --git a/packages/features/ee/workflows/lib/reminders/smsProviders/twilioProvider.ts b/packages/features/ee/workflows/lib/reminders/smsProviders/twilioProvider.ts
index 420c6159d5..6119550974 100644
--- a/packages/features/ee/workflows/lib/reminders/smsProviders/twilioProvider.ts
+++ b/packages/features/ee/workflows/lib/reminders/smsProviders/twilioProvider.ts
@@ -25,7 +25,7 @@ export const sendSMS = async (phoneNumber: string, body: string, sender: string)
body: body,
messagingServiceSid: process.env.TWILIO_MESSAGING_SID,
to: phoneNumber,
- from: sender,
+ from: sender ? sender : process.env.TWILIO_PHONE_NUMBER,
});
return response;
@@ -39,7 +39,7 @@ export const scheduleSMS = async (phoneNumber: string, body: string, scheduledDa
to: phoneNumber,
scheduleType: "fixed",
sendAt: scheduledDate,
- from: sender,
+ from: sender ? sender : process.env.TWILIO_PHONE_NUMBER,
});
return response;
diff --git a/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts b/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts
index ecc60d0bad..ffea491ba2 100644
--- a/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts
+++ b/packages/features/ee/workflows/lib/reminders/smsReminderManager.ts
@@ -10,6 +10,7 @@ import dayjs from "@calcom/dayjs";
import prisma from "@calcom/prisma";
import { Prisma } from "@calcom/prisma/client";
+import { getSenderId } from "../alphanumericSenderIdSupport";
import * as twilio from "./smsProviders/twilioProvider";
import customTemplate, { VariablesType } from "./templates/customTemplate";
import smsReminderTemplate from "./templates/smsReminderTemplate";
@@ -57,6 +58,8 @@ export const scheduleSMSReminder = async (
const timeUnit: timeUnitLowerCase | undefined = timeSpan.timeUnit?.toLocaleLowerCase() as timeUnitLowerCase;
let scheduledDate = null;
+ const senderID = getSenderId(reminderPhone, sender);
+
if (triggerEvent === WorkflowTriggerEvents.BEFORE_EVENT) {
scheduledDate = timeSpan.time && timeUnit ? dayjs(startTime).subtract(timeSpan.time, timeUnit) : null;
} else if (triggerEvent === WorkflowTriggerEvents.AFTER_EVENT) {
@@ -98,7 +101,7 @@ export const scheduleSMSReminder = async (
triggerEvent === WorkflowTriggerEvents.RESCHEDULE_EVENT
) {
try {
- await twilio.sendSMS(reminderPhone, message, sender);
+ await twilio.sendSMS(reminderPhone, message, senderID);
} catch (error) {
console.log(`Error sending SMS with error ${error}`);
}
@@ -117,7 +120,7 @@ export const scheduleSMSReminder = async (
reminderPhone,
message,
scheduledDate.toDate(),
- sender
+ senderID
);
await prisma.workflowReminder.create({
diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts
index d48ade52bd..aa895ff6c0 100644
--- a/packages/lib/constants.ts
+++ b/packages/lib/constants.ts
@@ -9,6 +9,7 @@ export const WEBSITE_URL = process.env.NEXT_PUBLIC_WEBSITE_URL || "https://cal.c
export const APP_NAME = process.env.NEXT_PUBLIC_APP_NAME || "Cal.com";
export const SUPPORT_MAIL_ADDRESS = process.env.NEXT_PUBLIC_SUPPORT_MAIL_ADDRESS || "help@cal.com";
export const COMPANY_NAME = process.env.NEXT_PUBLIC_COMPANY_NAME || "Cal.com, Inc.";
+export const SENDER_ID = process.env.NEXT_PUBLIC_SENDER_ID || "Cal";
// This is the URL from which all Cal Links and their assets are served.
// Use website URL to make links shorter(cal.com and not app.cal.com)
diff --git a/packages/trpc/server/routers/viewer/workflows.tsx b/packages/trpc/server/routers/viewer/workflows.tsx
index b4cd0aadfd..47b87bd94c 100644
--- a/packages/trpc/server/routers/viewer/workflows.tsx
+++ b/packages/trpc/server/routers/viewer/workflows.tsx
@@ -26,6 +26,7 @@ import {
deleteScheduledSMSReminder,
scheduleSMSReminder,
} from "@calcom/features/ee/workflows/lib/reminders/smsReminderManager";
+import { SENDER_ID } from "@calcom/lib/constants";
import { getErrorFromUnknown } from "@calcom/lib/errors";
import { TRPCError } from "@trpc/server";
@@ -154,7 +155,7 @@ export const workflowsRouter = router({
action: WorkflowActions.EMAIL_HOST,
template: WorkflowTemplates.REMINDER,
workflowId: workflow.id,
- sender: "Cal",
+ sender: SENDER_ID,
},
});
return { workflow };
@@ -469,7 +470,7 @@ export const workflowsRouter = router({
step.reminderBody || "",
step.id,
step.template,
- step.sender || "Cal"
+ step.sender || SENDER_ID
);
}
});
@@ -535,7 +536,7 @@ export const workflowsRouter = router({
emailSubject: newStep.template === WorkflowTemplates.CUSTOM ? newStep.emailSubject : null,
template: newStep.template,
numberRequired: newStep.numberRequired,
- sender: newStep.sender || "Cal",
+ sender: newStep.sender || SENDER_ID,
},
});
//cancel all reminders of step and create new ones (not for newEventTypes)
@@ -647,7 +648,7 @@ export const workflowsRouter = router({
newStep.reminderBody || "",
newStep.id || 0,
newStep.template,
- newStep.sender || "Cal"
+ newStep.sender || SENDER_ID
);
}
});
@@ -671,7 +672,7 @@ export const workflowsRouter = router({
addedSteps.forEach(async (step) => {
if (step) {
const newStep = step;
- newStep.sender = step.sender || "Cal";
+ newStep.sender = step.sender || SENDER_ID;
const createdStep = await ctx.prisma.workflowStep.create({
data: step,
});
@@ -760,7 +761,7 @@ export const workflowsRouter = router({
step.reminderBody || "",
createdStep.id,
step.template,
- step.sender || "Cal"
+ step.sender || SENDER_ID
);
}
});
@@ -897,7 +898,7 @@ export const workflowsRouter = router({
reminderBody,
0,
template,
- sender || "Cal"
+ sender || SENDER_ID
);
return { message: "Notification sent" };
}
diff --git a/turbo.json b/turbo.json
index c380af8b8c..3afb07c50c 100644
--- a/turbo.json
+++ b/turbo.json
@@ -183,6 +183,7 @@
"$TWILIO_TOKEN",
"$TWILIO_SID",
"$TWILIO_MESSAGING_SID",
+ "$TWILIO_PHONE_NUMBER",
"$CRON_API_KEY",
"$DAILY_API_KEY",
"$DAILY_SCALE_PLAN",
@@ -221,6 +222,7 @@
"$NEXT_PUBLIC_APP_NAME",
"$NEXT_PUBLIC_SUPPORT_MAIL_ADDRESS",
"$NEXT_PUBLIC_COMPANY_NAME",
+ "$NEXT_PUBLIC_SENDER_ID",
"$NEXTAUTH_COOKIE_DOMAIN",
"$NEXTAUTH_SECRET",
"$NEXTAUTH_URL",