-
Notifications
You must be signed in to change notification settings - Fork 354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add admin mailer. #103
Add admin mailer. #103
Changes from 17 commits
fad94df
a70edfa
14d3ca9
bbda648
1074e5c
e5484da
d12ea05
0a6a2da
f1e4067
62f4df1
f0fc32a
31071b1
ebd2e1e
f5f8307
07421de
97799c6
237850b
accb4c4
b136506
428b3a5
468ef61
552fe69
84e1b13
1f1a017
81585f7
1568777
3b8defc
04be4e3
1fbd525
6eb3369
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -271,6 +271,14 @@ If you prefer another host you can explore alternatives: | |
- [Community adapters](https://sveltesociety.dev/components#adapters) including Github pages, AppEngine, Azure, and more | ||
- [Supabase](https://supabase.com/docs/guides/getting-started/quickstarts/sveltekit) if you want one host for everything. Note: they do charge $10 a month for custom domains, unlike Cloudflare. | ||
|
||
## Setup Admin Emailer -- Optional | ||
|
||
SaaS Starter includes an admin emailer for sending yourself email notifications when important events happen. This let's you monitor your app and respond to users without watching the database. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix grammatical error: "setup" should be "set up". The word "setup" is a noun. The verb form is "set up". -If you setup the admin emailer, it will email you when users create their profile, or when the 'Contact Us' form is submitted.
+If you set up the admin emailer, it will email you when users create their profile, or when the 'Contact Us' form is submitted.
|
||
|
||
If you setup the admin emailer, it will email you when users create their profile or the 'Contact Us' form is submitted. You can add additional calls to sendAdminEmail() for any other events you want to monitor. | ||
|
||
To setup, provide email SMTP credientials in your environment variables: `PRIVATE_SMTP_HOST`, `PRIVATE_SMTP_PORT`, `PRIVATE_SMTP_USER`, `PRIVATE_SMTP_PASS`. You can use any SMTP providers such as Gmail, Sendgrid, AWS SES, Resend, or Mailgun. Then set the email address to which admin emails will be sent in `PRIVATE_ADMIN_EMAIL`. | ||
|
||
## Add Your Content | ||
|
||
After the steps above, you’ll have a working version like the demo page. However, it’s not branded, and doesn’t have your content. The following checklist helps you customize the template to make a SaaS homepage for your company. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,14 @@ | ||
# Supabase settings | ||
PUBLIC_SUPABASE_URL='https://REPLACE_ME.supabase.co' | ||
PUBLIC_SUPABASE_ANON_KEY='REPLACE_ME' | ||
PRIVATE_SUPABASE_SERVICE_ROLE='REPLACE_ME' | ||
|
||
# Stripe settings | ||
PRIVATE_STRIPE_API_KEY='REPLACE_ME' | ||
|
||
# SMTP settings for email - optional | ||
# PRIVATE_ADMIN_EMAIL='[email protected]' # see lib/admin_mailer.ts | ||
# PRIVATE_SMTP_HOST='REPLACE_ME' | ||
# PRIVATE_SMTP_PORT='587' | ||
# PRIVATE_SMTP_USER='REPLACE_ME' | ||
# PRIVATE_SMTP_PASS='REPLACE_ME' |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Optional dependency, only used if platform suppport node.js (not Cloudflare Workers). | ||
let nodemailer: typeof import("nodemailer") | undefined | ||
try { | ||
nodemailer = await import("nodemailer") | ||
} catch (e) { | ||
// nodemailer is not installed (Cloudflare Workers). Do nothing. | ||
} | ||
|
||
import { env } from "$env/dynamic/private" | ||
|
||
// Sends an email to the admin email address. | ||
// Does not throw errors, but logs them. | ||
export const sendAdminEmail = async ({ | ||
subject, | ||
body, | ||
}: { | ||
subject: string | ||
body: string | ||
}) => { | ||
// Check admin email is set. | ||
if (!env.PRIVATE_ADMIN_EMAIL) { | ||
return | ||
} | ||
|
||
// Chech if we have a valid nodemailer. | ||
const canCreateTransport = nodemailer?.createTransport | ||
if (canCreateTransport) { | ||
return await sendAdminEmailNodemailer({ subject, body }) | ||
} else { | ||
return await sendAdminEmailCloudflareWorkers({ subject, body }) | ||
} | ||
} | ||
|
||
const sendAdminEmailNodemailer = async ({ | ||
subject, | ||
body, | ||
}: { | ||
subject: string | ||
body: string | ||
}) => { | ||
if (!nodemailer) { | ||
console.log( | ||
"This environment does not support sending emails. Nodemailer requires node.js and doesn't work in environments like Cloudflare Workers.", | ||
) | ||
return | ||
} | ||
|
||
// Check if smtp settings are set. | ||
if ( | ||
!env.PRIVATE_SMTP_HOST || | ||
!env.PRIVATE_SMTP_USER || | ||
!env.PRIVATE_SMTP_PASS | ||
) { | ||
console.log( | ||
"No smtp settings, not sending admin email. See CMSaasStarter setup instructions.", | ||
) | ||
return | ||
} | ||
|
||
// Default to port 587 if not set. | ||
let port = 587 | ||
if (env.PRIVATE_SMTP_PORT) { | ||
port = parseInt(env.PRIVATE_SMTP_PORT) | ||
} | ||
|
||
try { | ||
const transporter = nodemailer.createTransport({ | ||
host: env.PRIVATE_SMTP_HOST, | ||
port: port, | ||
secure: port === 465, // https://nodemailer.com/smtp/ | ||
requireTLS: true, // Email should be encrypted in 2024 | ||
auth: { | ||
user: env.PRIVATE_SMTP_USER, | ||
pass: env.PRIVATE_SMTP_PASS, | ||
}, | ||
}) | ||
|
||
const info = await transporter.sendMail({ | ||
from: env.PRIVATE_ADMIN_EMAIL, | ||
to: env.PRIVATE_ADMIN_EMAIL, | ||
subject: "ADMIN_MAIL: " + subject, | ||
text: body, | ||
}) | ||
|
||
if (info.rejected && info.rejected.length > 0) { | ||
console.log("Failed to send admin email, rejected:", info.rejected) | ||
} | ||
} catch (e) { | ||
console.log("Failed to send admin email, error:", e) | ||
} | ||
} | ||
|
||
// https://blog.cloudflare.com/sending-email-from-workers-with-mailchannels/ | ||
const sendAdminEmailCloudflareWorkers = async ({ | ||
subject, | ||
body, | ||
}: { | ||
subject: string | ||
body: string | ||
}) => { | ||
const send_request = new Request("https://api.mailchannels.net/tx/v1/send", { | ||
method: "POST", | ||
headers: { | ||
"content-type": "application/json", | ||
}, | ||
body: JSON.stringify({ | ||
personalizations: [ | ||
{ | ||
to: [{ email: env.PRIVATE_ADMIN_EMAIL }], | ||
}, | ||
], | ||
from: { | ||
email: env.PRIVATE_ADMIN_EMAIL, | ||
}, | ||
subject: "ADMIN_MAIL: " + subject, | ||
content: [ | ||
{ | ||
type: "text/plain", | ||
value: body, | ||
}, | ||
], | ||
}), | ||
}) | ||
|
||
const response = await fetch(send_request) | ||
if (!response.ok) { | ||
console.log("Error sending admin email with MailChannels API", response.body) | ||
return | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix grammatical error: "Setup" should be "Set up".
The word "setup" is a noun. The verb form is "set up".
Committable suggestion