Skip to content

Commit

Permalink
use vercel
Browse files Browse the repository at this point in the history
  • Loading branch information
storm1729 committed Dec 28, 2024
1 parent cccb68f commit 9d4d693
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 22 deletions.
10 changes: 10 additions & 0 deletions src/app/[lang]/blog/smtp/smtp.md → _posts/smtp.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
---
title: What's Reacher's Secret for Accuracy?
lastUpdated: 28.12.2024
author:
name: Amaury
description: Reacher employs SMTP email verification to validate email addresses through commands like EHLO and RCPT TO. Positive responses confirm validity, while negative ones indicate issues. This method improves deliverability, reduces bounce rates, and supports efficient scaling of email verification.
ogImage:
url: /img/blog/smtp/cover.jpg
---

Reacher is [open-source](https://github.com/reacherhq/check-if-email-exists), so there's really no secret. But for those less familiar with the technical aspects, I'll explain a bit more here, hopefully in a beginner-friendly way. The secret is called **"SMTP email verification"**.

### How SMTP Email Verification Works
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"cors": "^2.8.5",
"date-fns": "^2.30.0",
"encoding": "^0.1.13",
"gray-matter": "^4.0.3",
"mailgun-js": "^0.22.0",
"markdown-pdf": "^11.0.0",
"marked-react": "^3.0.0",
Expand Down
File renamed without changes
File renamed without changes
Binary file removed public/img/storm1729.png
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,61 @@ import { Footer } from "@/components/Footer";
import { Nav } from "@/components/Nav/Nav";
import { dictionary } from "@/dictionaries";
import { Button, Container, Text } from "@mantine/core";
import fs from "fs";
import Markdown from "marked-react";
import { DLink } from "@/components/DLink";
import Image from "next/image";
import { getAllPosts, getPostBySlug } from "@/util/blog";
import { Metadata } from "next";
import { notFound } from "next/navigation";

// Cover ideas:
// - https://unsplash.com/s/photos/geometric-pattern
// - https://stephaniewalter.design/blog/how-to-make-your-blog-images-stand-out-reflect-your-identity/
import cover from "./cover.jpg";

export const metadata = {
title: "What's Reacher's Secret for Accuracy?",
description:
"Reacher employs SMTP email verification to validate email addresses through commands like EHLO and RCPT TO. Positive responses confirm validity, while negative ones indicate issues. This method improves deliverability, reduces bounce rates, and supports efficient scaling of email verification.",
author: "Amaury",
lastUpdated: "28.12.2024",
type Params = {
params: Promise<{
slug: string;
}>;
};

export async function generateMetadata(props: Params): Promise<Metadata> {
const params = await props.params;
const blogPost = getPostBySlug(params.slug);
if (!blogPost) {
return notFound();
}

return {
title: blogPost.title,
description: blogPost.description,
openGraph: {
title: blogPost.title,
images: [blogPost.ogImage.url],
},
};
}

export default async function Smtp({
params: { lang },
params: { lang, slug },
}: {
params: { lang: string };
params: { lang: string; slug: string };
}) {
const d = await dictionary(lang);
const blog = fs
.readFileSync("./src/app/[lang]/blog/smtp/smtp.md")
.toString();
const blogPost = getPostBySlug(slug);
if (!blogPost) {
return notFound();
}

return (
<>
<Nav d={d} page="blog" />

<Container mt="xl" size="45rem">
<div className="text-center">
<h1>{metadata.title}</h1>
<h1>{blogPost.title}</h1>
<Text mb="xl">
{d.blog.author}: {metadata.author}.{" "}
{d.blog.last_updated}: {metadata.lastUpdated}.
{d.blog.author}: {blogPost.author.name}.{" "}
{d.blog.last_updated}: {blogPost.lastUpdated}.
</Text>
</div>

Expand All @@ -52,14 +69,14 @@ export default async function Smtp({
}}
>
<Image
src={cover}
alt={metadata.title}
src={blogPost.ogImage.url}
alt={blogPost.title}
fill
objectFit="cover"
/>
</div>

<Markdown>{blog}</Markdown>
<Markdown>{blogPost.content}</Markdown>
</Container>

<div className="text-center">
Expand All @@ -74,3 +91,11 @@ export default async function Smtp({
</>
);
}

export async function generateStaticParams() {
const posts = getAllPosts();

return posts.map((post) => ({
slug: post.slug,
}));
}
5 changes: 3 additions & 2 deletions src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ export const config = {
* - _next/image (image optimization files)
* - favicon (favicon file)
* - monitoring (health check)
* - js (JavaScript files)
* - img (static images, in /public)
* - js (JavaScript files, in /public)
* - v0,v1 (api.reacher.email/v0/...)
* - version (api.reacher.email/version)
*/
"/((?!api|_next/static|_next/image|favicon|monitoring|js|v0|v1|version).*)",
"/((?!api|_next/static|_next/image|favicon|monitoring|img|js|v0|v1|version).*)",
],
};

Expand Down
45 changes: 45 additions & 0 deletions src/util/blog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { join } from "path";
import fs from "fs";
import matter from "gray-matter";

type Author = {
name: string;
picture: string;
};

type Post = {
slug: string;
title: string;
lastUpdated: string;
description: string; // For SEO
author: Author;
content: string;
ogImage: {
url: string;
};
};
const postsDirectory = join(process.cwd(), "_posts");

export function getPostSlugs() {
return fs.readdirSync(postsDirectory);
}

export function getPostBySlug(slug: string) {
const realSlug = slug.replace(/\.md$/, "");
const fullPath = join(postsDirectory, `${realSlug}.md`);
const fileContents = fs.readFileSync(fullPath, "utf8");
const { data, content } = matter(fileContents);

return { ...data, slug: realSlug, content } as Post;
}

export function getAllPosts(): Post[] {
const slugs = getPostSlugs();
const posts = slugs
.map((slug) => getPostBySlug(slug))
// sort posts by date in descending order
.sort((post1, post2) =>
post1.lastUpdated > post2.lastUpdated ? -1 : 1
);
return posts;
}
50 changes: 49 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3791,7 +3791,7 @@ arg@^5.0.1:
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==

argparse@^1.0.10:
argparse@^1.0.10, argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
Expand Down Expand Up @@ -5712,6 +5712,13 @@ express@^4.17.1:
utils-merge "1.0.1"
vary "~1.1.2"

extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==
dependencies:
is-extendable "^0.1.0"

extend@^3.0.0, extend@^3.0.2, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
Expand Down Expand Up @@ -6326,6 +6333,16 @@ graphemer@^1.4.0:
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==

gray-matter@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798"
integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==
dependencies:
js-yaml "^3.13.1"
kind-of "^6.0.2"
section-matter "^1.0.0"
strip-bom-string "^1.0.0"

gunzip-maybe@^1.4.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac"
Expand Down Expand Up @@ -6828,6 +6845,11 @@ is-docker@^2.0.0, is-docker@^2.1.1:
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==

is-extendable@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==

is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
Expand Down Expand Up @@ -7032,6 +7054,14 @@ javascript-stringify@^2.0.1:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==

js-yaml@^3.13.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"

js-yaml@^4.0.0, js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
Expand Down Expand Up @@ -7187,6 +7217,11 @@ keyv@^4.5.3:
dependencies:
json-buffer "3.0.1"

kind-of@^6.0.0, kind-of@^6.0.2:
version "6.0.3"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==

klaw@^1.0.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439"
Expand Down Expand Up @@ -9528,6 +9563,14 @@ scheduler@^0.23.0:
dependencies:
loose-envify "^1.1.0"

section-matter@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167"
integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==
dependencies:
extend-shallow "^2.0.1"
kind-of "^6.0.0"

[email protected]:
version "6.1.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.1.1.tgz#53f53da9b30b2103cd4f15eab3a18ecbcb210c9b"
Expand Down Expand Up @@ -9984,6 +10027,11 @@ strip-ansi@^6.0.1:
dependencies:
ansi-regex "^5.0.1"

strip-bom-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92"
integrity sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==

strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
Expand Down

0 comments on commit 9d4d693

Please sign in to comment.