1import LogoFrappeMail from "@/assets/images/frappe-mail.svg";
2import LogoGmail from "@/assets/images/gmail.png";
3import LogoOutlook from "@/assets/images/outlook.png";
4import LogoSendgrid from "@/assets/images/sendgrid.png";
5import LogoSparkpost from "@/assets/images/sparkpost.webp";
6import LogoYahoo from "@/assets/images/yahoo.png";
7import LogoYandex from "@/assets/images/yandex.png";
8import LogoFrappeMail from "@/assets/images/frappe-mail.svg";
9import { EmailAccount, EmailService, RenderField } from "@/types";
10import { validateEmailWithZod } from "@/utils";
11import { __ } from "@/translation";
12
13type EmailAccountFormState = {
14 email_account_name?: string;
15 email_id?: string;
16 service?: string;
17 password?: string;
18 api_key?: string;
19 api_secret?: string;
20 frappe_mail_site?: string;
21 domain?: string;
22 email_server?: string;
23 incoming_port?: string | number;
24 smtp_server?: string;
25 smtp_port?: string | number;
26 use_ssl?: boolean | number;
27 use_starttls?: boolean | number;
28 use_tls?: boolean | number;
29 use_ssl_for_outgoing?: boolean | number;
30 validate_ssl_certificate?: boolean | number;
31 validate_ssl_certificate_for_outgoing?: boolean | number;
32 attachment_limit?: string | number;
33 append_emails_to_sent_folder?: boolean | number;
34 sent_folder_name?: string;
35};
36
37const fixedFields: RenderField[] = [
38 {
39 label: __("Account name"),
40 name: "email_account_name",
41 type: "text",
42 placeholder: __("Support / Sales"),
43 },
44 {
45 label: __("Email ID"),
46 name: "email_id",
47 type: "email",
48 placeholder: __("johndoe@example.com"),
49 },
50];
51
52export const incomingOutgoingFields: RenderField[] = [
53 {
54 label: __("Enable Incoming"),
55 name: "enable_incoming",
56 type: "checkbox",
57 description: __(
58 "If enabled, tickets can be created from the incoming emails on this account."
59 ),
60 },
61 {
62 label: __("Enable Outgoing"),
63 name: "enable_outgoing",
64 type: "checkbox",
65 description: __(
66 "If enabled, outgoing emails can be sent from this account."
67 ),
68 },
69 {
70 label: __("Default Incoming"),
71 name: "default_incoming",
72 type: "checkbox",
73 description: __(
74 "If enabled, all replies to your company (eg: replies@yourcompany.com) will come to this account. Note: Only one account can be default incoming."
75 ),
76 },
77 {
78 label: __("Default Outgoing"),
79 name: "default_outgoing",
80 type: "checkbox",
81 description: __(
82 "If enabled, all outgoing emails will be sent from this account. Note: Only one account can be default outgoing."
83 ),
84 },
85];
86
87export const popularProviderFields = [
88 ...fixedFields,
89 {
90 label: __("Password"),
91 name: "password",
92 type: "password",
93 placeholder: "********",
94 },
95];
96
97export const frappeMailFields = [
98 ...fixedFields,
99 {
100 label: __("Frappe Mail site"),
101 name: "frappe_mail_site",
102 type: "text",
103 placeholder: "https://frappemail.com",
104 },
105 {
106 label: __("API Key"),
107 name: "api_key",
108 type: "text",
109 placeholder: "********",
110 },
111 {
112 label: __("API Secret"),
113 name: "api_secret",
114 type: "password",
115 placeholder: "********",
116 },
117];
118
119export const customProviderTopFields = [
120 ...fixedFields,
121 {
122 label: __("Password"),
123 name: "password",
124 type: "password",
125 placeholder: "********",
126 },
127 {
128 label: __("Email Domain"),
129 name: "domain",
130 type: "text",
131 placeholder: __("example.com"),
132 },
133];
134
135export const customIncomingFields = [
136 {
137 label: __("Incoming Server (IMAP/POP)"),
138 name: "email_server",
139 type: "text",
140 placeholder: __("imap.example.com"),
141 },
142 {
143 label: __("Incoming Port"),
144 name: "incoming_port",
145 type: "text",
146 placeholder: "993",
147 },
148 {
149 label: __("Use SSL for Incoming"),
150 name: "use_ssl",
151 type: "checkbox",
152 placeholder: "",
153 },
154 {
155 label: __("Use TLS for Incoming"),
156 name: "use_starttls",
157 type: "checkbox",
158 placeholder: "",
159 },
160];
161
162export const customOutgoingFields = [
163 {
164 label: __("Outgoing Server (SMTP)"),
165 name: "smtp_server",
166 type: "text",
167 placeholder: "smtp.example.com",
168 },
169 {
170 label: __("Outgoing Port"),
171 name: "smtp_port",
172 type: "text",
173 placeholder: "587",
174 },
175 {
176 label: __("Use SSL for Outgoing"),
177 name: "use_ssl_for_outgoing",
178 type: "checkbox",
179 placeholder: "",
180 },
181 {
182 label: __("Use TLS for Outgoing"),
183 name: "use_tls",
184 type: "checkbox",
185 placeholder: "",
186 },
187];
188
189export const customProviderFields = customProviderTopFields;
190
191export const services: EmailService[] = [
192 {
193 name: "GMail",
194 icon: LogoGmail,
195 info: __(`Setting up GMail requires you to enable two factor authentication
196 and app specific passwords. Read more`),
197 link: "https://support.google.com/accounts/answer/185833",
198 custom: false,
199 },
200 {
201 name: "Outlook",
202 icon: LogoOutlook,
203 info: __(`Setting up Outlook requires you to enable two factor authentication
204 and app specific passwords. Read more`),
205 link: "https://support.microsoft.com/en-us/account-billing/how-to-get-and-use-app-passwords-5896ed9b-4263-e681-128a-a6f2979a7944",
206 custom: false,
207 },
208 {
209 name: "Sendgrid",
210 icon: LogoSendgrid,
211 info: __(`Setting up Sendgrid requires you to enable two factor authentication
212 and app specific passwords. Read more`),
213 link: "https://sendgrid.com/docs/ui/account-and-settings/two-factor-authentication/",
214 custom: false,
215 },
216 {
217 name: "SparkPost",
218 icon: LogoSparkpost,
219 info: __(`Setting up SparkPost requires you to enable two factor authentication
220 and app specific passwords. Read more`),
221 link: "https://support.sparkpost.com/docs/my-account-and-profile/enabling-two-factor-authentication",
222 custom: false,
223 },
224 {
225 name: "Yahoo",
226 icon: LogoYahoo,
227 info: __(`Setting up Yahoo requires you to enable two factor authentication
228 and app specific passwords. Read more`),
229 link: "https://help.yahoo.com/kb/SLN15241.html",
230 custom: false,
231 },
232 {
233 name: "Yandex",
234 icon: LogoYandex,
235 info: __(`Setting up Yandex requires you to enable two factor authentication
236 and app specific passwords. Read more`),
237 link: "https://yandex.com/support/id/authorization/app-passwords.html",
238 custom: false,
239 },
240 {
241 name: "Frappe Mail",
242 icon: LogoFrappeMail,
243 info: __(
244 `Setting up Frappe Mail requires you to have an API key and API Secret of your email account. Read more`
245 ),
246 link: "https://github.com/frappe/mail",
247 custom: true,
248 },
249 {
250 name: "Custom",
251 icon: "",
252 info: __(`Use your own IMAP/SMTP settings. Open in Desk`),
253 link: "/desk/email-account/new-email-account",
254 custom: true,
255 },
256];
257
258export const emailIcon = {
259 GMail: LogoGmail,
260 Outlook: LogoOutlook,
261 Sendgrid: LogoSendgrid,
262 SparkPost: LogoSparkpost,
263 Yahoo: LogoYahoo,
264 Yandex: LogoYandex,
265 // service names Frappe stores for these providers
266 "Outlook.com": LogoOutlook,
267 "Yahoo Mail": LogoYahoo,
268 "Yandex.Mail": LogoYandex,
269 "Frappe Mail": LogoFrappeMail,
270 Custom: "",
271};
272
273export function validateInputs(
274 state: EmailAccountFormState,
275 service: string,
276 allowMissingPassword = false
277) {
278 if (!state.email_account_name) {
279 return __("Account name is required");
280 }
281 if (!state.email_id) {
282 return __("Email ID is required");
283 }
284 const validEmail = validateEmailWithZod(state.email_id);
285 if (!validEmail) {
286 return __("Invalid email ID");
287 }
288 if (service === "Frappe Mail") {
289 if (!state.api_key) {
290 return __("API Key is required");
291 }
292 if (!state.api_secret) {
293 return __("API Secret is required");
294 }
295 return "";
296 }
297 if (service === "Custom") {
298 const hasDomain = Boolean(state.domain);
299 const hasManualServers =
300 state.email_server &&
301 state.incoming_port &&
302 state.smtp_server &&
303 state.smtp_port;
304 if (!hasDomain && !hasManualServers) {
305 return __("Email Domain or manual server settings are required");
306 }
307 if (!state.password && !allowMissingPassword) {
308 return __("Password is required");
309 }
310 return "";
311 }
312 if (!state.password && !allowMissingPassword) {
313 return __("Password is required");
314 }
315 return "";
316}
317