Skip to content
This repository was archived by the owner on Apr 19, 2021. It is now read-only.

Commit 8ff4e32

Browse files
committed
send mail through function
1 parent 0780db5 commit 8ff4e32

File tree

9 files changed

+12140
-23551
lines changed

9 files changed

+12140
-23551
lines changed

.babelrc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"presets": [
3+
"@babel/preset-typescript",
4+
[
5+
"@babel/preset-env",
6+
{
7+
"targets": {
8+
"node": "6.10.3"
9+
}
10+
}
11+
]
12+
],
13+
"plugins": [
14+
"@babel/plugin-proposal-class-properties",
15+
"@babel/plugin-transform-object-assign",
16+
"@babel/plugin-proposal-object-rest-spread"
17+
]
18+
}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,7 @@ $RECYCLE.BIN/
113113

114114
# Windows shortcuts
115115
*.lnk
116+
117+
# Local Netlify folder
118+
.netlify
119+
lambda

netlify.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
[build]
2+
command = "yarn build"
3+
functions = "lambda"
4+
15
[[redirects]]
26
from = "/gitpod-business.html"
37
to = "/pricing/#enterprise"

package-lock.json

Lines changed: 4834 additions & 16938 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
],
99
"main": "n/a",
1010
"scripts": {
11-
"build": "cp -r src/docs/release-notes/* static/release-notes/ && gatsby build",
11+
"build": "cp -r src/docs/release-notes/* static/release-notes/ && gatsby build && npx netlify-lambda build src/functions",
1212
"clean": "rimraf public",
1313
"deploy": "gatsby build --prefix-paths && gh-pages -d public",
1414
"dev": "env-cmd -f .env.development gatsby develop",
@@ -62,15 +62,19 @@
6262
"react-helmet": "^6.0.0",
6363
"react-modal-video": "^1.2.3",
6464
"react-tweet-embed": "^1.2.2",
65-
"typescript": "^3.9.3"
65+
"typescript": "^3.9.3",
66+
"@sendgrid/mail": "^7.2.6"
6667
},
6768
"devDependencies": {
69+
"@types/aws-lambda": "^8.10.63",
6870
"@types/classnames": "^2.2.10",
6971
"@types/node": "^14.0.6",
7072
"@types/react": "^16.9.35",
7173
"@types/react-dom": "^16.9.8",
7274
"@types/react-helmet": "^6.0.0",
7375
"gh-pages": "^3.0.0",
76+
"netlify-cli": "^2.64.1",
77+
"netlify-lambda": "^2.0.1",
7478
"prettier": "^2.0.5",
7579
"rimraf": "^3.0.2",
7680
"tslint": "^6.1.2",

src/functions/submit-form.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { APIGatewayEvent, Context } from 'aws-lambda';
2+
import * as client from '@sendgrid/mail';
3+
4+
export interface Email {
5+
to?: {
6+
email: string,
7+
name?: string
8+
},
9+
from: {
10+
email: string,
11+
name?: string
12+
}
13+
subject: string,
14+
message: string
15+
}
16+
17+
async function sendEmail(client: client.MailService, email: Email): Promise<{statusCode: number, errorMessage?: string}> {
18+
const data: client.MailDataRequired = {
19+
from: email.from,
20+
subject: email.subject,
21+
to: [
22+
email.to!
23+
],
24+
content: [
25+
{
26+
type: "text/plain",
27+
value: email.message
28+
}
29+
]
30+
}
31+
try {
32+
await client.send(data);
33+
return {
34+
statusCode: 200
35+
}
36+
} catch (e) {
37+
return {
38+
statusCode: 500,
39+
errorMessage: `Error : ${JSON.stringify(e)}`
40+
}
41+
}
42+
}
43+
44+
exports.handler = function (event: APIGatewayEvent, _: Context, callback: any) {
45+
46+
console.log(JSON.stringify(event.body));
47+
const SENDGRID_API_KEY = process.env.SENDGRID_API_KEY || 'no-key';
48+
const SENDGRID_TO_EMAIL = process.env.SENDGRID_TO_EMAIL || '[email protected]';
49+
50+
const email: Email = JSON.parse(event.body!) as Email;
51+
52+
email.to = {
53+
email: SENDGRID_TO_EMAIL,
54+
name: 'Gitpod'
55+
}
56+
57+
client.setApiKey(SENDGRID_API_KEY);
58+
sendEmail(
59+
client,
60+
email
61+
).then(response => callback(null, { statusCode: response.statusCode, body: email + " added" }))
62+
.catch(err => callback(err, null));
63+
};

src/pages/contact.tsx

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import styled from '@emotion/styled'
33
import IndexLayout from '../layouts'
44
import { sizes, borders } from '../styles/variables'
55
import SubmissionSucess from '../components/SubmissionSucess'
6+
import { Email } from '../functions/submit-form'
67

78
const StyledContactPage = styled.div`
89
/* --------------------------------------------- */
@@ -74,15 +75,6 @@ const StyledContactPage = styled.div`
7475
}
7576
`
7677

77-
export function encode(data: { [k: string]: string | number | boolean | null | undefined }) {
78-
return Object.keys(data)
79-
.map((key) => {
80-
const value = data[key]
81-
return encodeURIComponent(key) + '=' + (value === null || value === undefined ? 'null' : encodeURIComponent(value))
82-
})
83-
.join('&')
84-
}
85-
8678
const subjects: string[] = [
8779
'I have a question regarding Gitpod Self-Hosted',
8880
'I have a question regarding Gitpod Education',
@@ -95,7 +87,7 @@ export default function ContactPage(props: any) {
9587
const [state, setState] = React.useState<{
9688
name?: string
9789
consent?: boolean
98-
eMail?: string
90+
email?: string
9991
subject?: string
10092
message?: string
10193
messageSent?: boolean
@@ -130,7 +122,7 @@ export default function ContactPage(props: any) {
130122

131123
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
132124
e.preventDefault()
133-
if (!state.eMail) {
125+
if (!state.email) {
134126
setState({
135127
...state,
136128
errorMessage: 'Please provide a valid email address so that we can reply to you.'
@@ -151,14 +143,19 @@ export default function ContactPage(props: any) {
151143
})
152144
return
153145
}
154-
const form = e.target as HTMLFormElement
155-
fetch('/contact/', {
146+
147+
const email: Email = {
148+
from: {
149+
email: state.email,
150+
name: state.name
151+
},
152+
subject: state.subject + ' (from ' + state.email + ')',
153+
message: state.message
154+
};
155+
156+
fetch('/.netlify/functions/submit-form', {
156157
method: 'POST',
157-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
158-
body: encode({
159-
'form-name': form.getAttribute('name'),
160-
...state
161-
})
158+
body: JSON.stringify(email)
162159
})
163160
.then(() =>
164161
setState({
@@ -179,8 +176,6 @@ export default function ContactPage(props: any) {
179176
className="form"
180177
method="POST"
181178
name="Contact"
182-
data-netlify="true"
183-
data-netlify-honeypot="bot-field"
184179
onSubmit={handleSubmit}
185180
>
186181
<input type="hidden" name="form-name" value="contact" />
@@ -206,15 +201,15 @@ export default function ContactPage(props: any) {
206201
id="Name"
207202
onChange={handleChange}
208203
/>
209-
<label className="visually-hidden" htmlFor="eMail">
204+
<label className="visually-hidden" htmlFor="email">
210205
E-Mail
211206
</label>
212207
<input
213-
name="eMail"
208+
name="email"
214209
className="form__input form__input--half"
215210
type="email"
216211
placeholder="E-mail"
217-
id="eMail"
212+
id="email"
218213
onChange={handleChange}
219214
/>
220215
<div className="subject">

src/pages/enterprise-license.tsx

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import styled from '@emotion/styled'
44
import { borders, colors } from '../styles/variables'
55
import { countryList } from '../contents/license-key'
66
import { isEurope } from '../utils/helpers'
7-
import { encode } from './contact'
87
import SubmissionSucess from '../components/SubmissionSucess'
98
import { Link } from 'gatsby'
9+
import { Email } from '../functions/submit-form';
10+
1011
const StyledEnterpriseLicensePage = styled.div`
1112
form {
1213
padding: 5rem 0;
@@ -260,14 +261,30 @@ const EnterpriseLicensePage = () => {
260261
return
261262
}
262263

263-
const form = e.target as HTMLFormElement
264-
fetch('/enterprise-license/', {
264+
const email: Email = {
265+
from: {
266+
email: state.email,
267+
name: state.firstName + ' ' + state.lastName
268+
},
269+
subject: 'Requesting a professional self-hosted license (from ' + state.email + ')',
270+
message: `
271+
${state.company}
272+
${state.firstName} ${state.lastName}
273+
${state.address}
274+
${state.postalCode} ${state.city}
275+
${state.country}
276+
277+
domain: ${state.domain}
278+
seats: ${state.seats}
279+
employees: ${state.noOfEmployees}
280+
281+
Message:
282+
${state.message}
283+
`
284+
};
285+
fetch('/.netlify/functions/submit-form', {
265286
method: 'POST',
266-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
267-
body: encode({
268-
'form-name': form.getAttribute('name'),
269-
...state
270-
})
287+
body: JSON.stringify(email)
271288
})
272289
.then(() =>
273290
setState({

0 commit comments

Comments
 (0)