Unlike in Bob's B&B task where you mock-sent emails, here you'll learn how to send real emails.
Sending email must happen from your server-side rather than client-side code, as you'll need to send email with an API key which you must keep private/secret and not expose in client-side code.
This assumes that you have a repo with an existing website in it, which you run locally and in production with bun via a server.js like this:
let server = Bun.serve({
routes: {
'/*': () => new Response(`Welcome to CMS! ${Math.random()}`),
// ... other routes
}
})
console.log(`Listening on ${server.url}`)
You'll be making an account with SendGrid and sending emails via their API.
.env file in the root of your repo (create one if you don't have one) add the line SENDGRID_API_KEY=whatever_your_key_isNote that sendgrid's free tier is limited to 100 emails/day.
email.js file in your repoexport async function sendEmail ({ to, from, subject, body }) {
let SENDGRID_API_KEY = process.env.SENDGRID_API_KEY
if (!SENDGRID_API_KEY) {
console.error('Environment variable SENDGRID_API_KEY not set')
console.error('Create a .env file with SENDGRID_API_KEY=your_key_here in the root of your repo')
return
}
let result = await fetch('https://api.sendgrid.com/v3/mail/send', {
method: 'POST',
body: JSON.stringify({
'personalizations': [{ 'to': [{ 'email': to }] }],
'from': { 'email': from },
'subject': subject,
'content': [{ 'type': 'text/plain', 'value': body.trim().replace(/\n +/gm, '\n') }]
}),
headers: {
'Authorization': `Bearer ${SENDGRID_API_KEY}`,
'content-type': 'application/json',
},
})
console.log(result)
}
test-email.js file in your repoimport { sendEmail } from './email.js'
sendEmail({
to: 'jgordon@cms.tela.org.uk',
from: 'jgordon@cms.tela.org.uk',
subject: 'This is a test email',
body: `
This is the body of my email.
This is another line of my email.
Lots of Love,
Mr Gordon
`
})
test-email.js to have your email rather than mine as the from and to addressesbun test-email.js
POST routeYou probably want sending the email to be triggered by something that happens on your website. For that, something in your client-side code needs to trigger a POST request to your server, which then runs the sendEmail() function.
Most request to your server will be GET requests. When you want to trigger an action such as sending an email or saving something to a database, you should use POST requests instead, which means using Hono's app.post() instead of app.get(). You're going to make a POST route for /email by first importing email.js at the top of your server.js:
import { sendEmail } from './email.js'
Then, add the following route to Bun.serve({ routes: { ... } }):
'/email': {
POST: () => {
sendEmail({
to: '_your_email_',
from: '_your_email_', // must be the email address you verified
subject: 'This is the email subject',
body: 'This is the body of the email'
})
return new Response('ok')
}
}
You'll need to make a POST request to /email to see if it actually works, which we'll do in the next step.
POSTing from a web pageCreate a send-email.html or other client-side HTML file with this, probably in your ./public folder:
<!doctype html>
<title>Email test</title>
<button id="send">Email me</button>
<p id="sent" style="display: none;">Email sent!</p>
<script>
send.onclick = () => {
fetch(`/email`, { method: 'POST' })
send.style.display = 'none'
sent.style.display = 'block'
}
</script>
Then:
bun server.jsAssuming it works locally, it should work on your actual online website too. This comes with a caveat/warning that you should probably be doing a fair amount of error handling, rate limiting and other things if you were to do this for real-real.
Ideally you shouldn't add the .env file to git, and instead ignore it with a .gitignore file. However, this isn't currently possible with how I'm hosting your website.
You probably want the user to be able to customise some aspects of the emails that get sent, such as the title, body, to address and/or from address. To do that, you'll need to send some extra data (the 'body') through with the fetch() POST request from the client-side code, then do something with that data in the server-side code for the route.
You may also want to check the docs on sendgrid for how you can customise the emails.