Repository: CH563/fakemail Branch: main Commit: d6cabf7f4a33 Files: 73 Total size: 158.4 KB Directory structure: gitextract_oaqzapim/ ├── .gitignore ├── LICENSE ├── README.md ├── app/ │ ├── .gitignore │ ├── .vscode/ │ │ ├── extensions.json │ │ └── launch.json │ ├── README.md │ ├── astro.config.mjs │ ├── components.json │ ├── email-platform-schema.sql │ ├── env.d.ts │ ├── package.json │ ├── public/ │ │ └── robots.txt │ ├── src/ │ │ ├── components/ │ │ │ ├── Bar.astro │ │ │ ├── Container.tsx │ │ │ ├── Footer.astro │ │ │ ├── Generator.tsx │ │ │ ├── Header.astro │ │ │ ├── Lists.tsx │ │ │ ├── Main.astro │ │ │ ├── ModeToggle.tsx │ │ │ ├── mail/ │ │ │ │ ├── AccountSwitcher.tsx │ │ │ │ ├── Accounts.tsx │ │ │ │ ├── Mail.tsx │ │ │ │ ├── MailDisplay.tsx │ │ │ │ ├── MailList.tsx │ │ │ │ ├── Nav.tsx │ │ │ │ ├── data.tsx │ │ │ │ └── useMail.ts │ │ │ └── ui/ │ │ │ ├── alert-dialog.tsx │ │ │ ├── avatar.tsx │ │ │ ├── badge.tsx │ │ │ ├── button.tsx │ │ │ ├── dialog.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├── input.tsx │ │ │ ├── mail-card.tsx │ │ │ ├── resizable.tsx │ │ │ ├── scroll-area.tsx │ │ │ ├── select.tsx │ │ │ ├── separator.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── sonner.tsx │ │ │ ├── textarea.tsx │ │ │ └── tooltip.tsx │ │ ├── hooks/ │ │ │ ├── useCopyToClipboard.ts │ │ │ └── useGeneratorMail.ts │ │ ├── layouts/ │ │ │ └── Layout.astro │ │ ├── lib/ │ │ │ ├── demo.ts │ │ │ ├── store.ts │ │ │ └── utils.ts │ │ ├── middleware.ts │ │ ├── pages/ │ │ │ ├── api/ │ │ │ │ ├── delete.ts │ │ │ │ ├── deleteMails.ts │ │ │ │ ├── generate.ts │ │ │ │ ├── get.ts │ │ │ │ ├── getMails.ts │ │ │ │ ├── remarkMail.ts │ │ │ │ └── updateStatus.ts │ │ │ ├── dashboard.astro │ │ │ ├── index.astro │ │ │ ├── settings.astro │ │ │ ├── sign-in.astro │ │ │ └── sign-up.astro │ │ └── styles/ │ │ └── globals.css │ ├── tailwind.config.mjs │ ├── tsconfig.json │ └── wrangler.example.toml └── mailbox/ ├── package.json ├── src/ │ ├── index.ts │ └── insertMails.ts ├── tsconfig.json └── wrangler.toml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* .pnpm-debug.log* .wrangler # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage *.lcov # nyc test coverage .nyc_output # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # Snowpack dependency directory (https://snowpack.dev/) web_modules/ # TypeScript cache *.tsbuildinfo # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional stylelint cache .stylelintcache # Microbundle cache .rpt2_cache/ .rts2_cache_cjs/ .rts2_cache_es/ .rts2_cache_umd/ # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variable files .env .env.development.local .env.test.local .env.production.local .env.local # parcel-bundler cache (https://parceljs.org/) .cache .parcel-cache # Next.js build output .next out # Nuxt.js build / generate output .nuxt dist # Gatsby files .cache/ # Comment in the public line in if your project uses Gatsby and not Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public # vuepress build output .vuepress/dist # vuepress v2.x temp and cache directory .temp .cache # Docusaurus cache and generated files .docusaurus # Serverless directories .serverless/ # FuseBox cache .fusebox/ # DynamoDB Local files .dynamodb/ # TernJS port file .tern-port # Stores VSCode versions used for testing VSCode extensions .vscode-test # yarn v2 .yarn/cache .yarn/unplugged .yarn/build-state.yml .yarn/install-state.gz .pnp.* ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2025 Chenliwen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Fake Mail - The free temporary email service ![](./images/fakemail.png) 📪 Website: [https://mail.fakeact.fun](https://mail.fakeact.fun) ## Fake email generator, delete emails 2 hours after receiving This is a temporary email service that uses Cloudflare Workers to create a temporary email address and view the received email in web browser. ` /app ` - Astro ssr ` /mailbox ` - Cloudflare Worker ## Multiple email addresses use [clerk](https://clerk.com/) to login && register Data is stored encrypted on cloudflare D1 ## License Fake Mail is licensed under the [MIT License](https://github.com/CH563/fakemail/blob/main/LICENSE). ================================================ FILE: app/.gitignore ================================================ # build output dist/ # generated types .astro/ # dependencies node_modules/ # logs npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* # environment variables .env .env.production # macOS-specific files .DS_Store # jetbrains setting folder .idea/ wrangler.toml worker-configuration.d.ts .env.example ================================================ FILE: app/.vscode/extensions.json ================================================ { "recommendations": ["astro-build.astro-vscode"], "unwantedRecommendations": [] } ================================================ FILE: app/.vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { "command": "./node_modules/.bin/astro dev", "name": "Development server", "request": "launch", "type": "node-terminal" } ] } ================================================ FILE: app/README.md ================================================ # Astro Starter Kit: Basics ```sh npm create astro@latest -- --template basics ``` [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics) [![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics) [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json) > 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! ![just-the-basics](https://github.com/withastro/astro/assets/2244813/a0a5533c-a856-4198-8470-2d67b1d7c554) ## 🚀 Project Structure Inside of your Astro project, you'll see the following folders and files: ```text / ├── public/ │ └── favicon.svg ├── src/ │ ├── layouts/ │ │ └── Layout.astro │ └── pages/ │ └── index.astro └── package.json ``` To learn more about the folder structure of an Astro project, refer to [our guide on project structure](https://docs.astro.build/en/basics/project-structure/). ## 🧞 Commands All commands are run from the root of the project, from a terminal: | Command | Action | | :------------------------ | :----------------------------------------------- | | `npm install` | Installs dependencies | | `npm run dev` | Starts local dev server at `localhost:4321` | | `npm run build` | Build your production site to `./dist/` | | `npm run preview` | Preview your build locally, before deploying | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | | `npm run astro -- --help` | Get help using the Astro CLI | ## 👀 Want to learn more? Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). ================================================ FILE: app/astro.config.mjs ================================================ // @ts-check import { defineConfig } from 'astro/config'; import react from '@astrojs/react'; import tailwind from '@astrojs/tailwind'; import cloudflare from '@astrojs/cloudflare'; import clerk from '@clerk/astro'; // https://astro.build/config export default defineConfig({ output: 'server', site: 'https://mail.fakeact.fun', integrations: [react(), tailwind({ applyBaseStyles: false, }), clerk()], adapter: cloudflare({ platformProxy: { enabled: true, configPath: 'wrangler.toml' } }), vite: { resolve: { // Use react-dom/server.edge instead of react-dom/server.browser for React 19. // Without this, MessageChannel from node:worker_threads needs to be polyfilled. alias: import.meta.env.PROD ? { "react-dom/server": "react-dom/server.edge", } : {}, } } }); ================================================ FILE: app/components.json ================================================ { "$schema": "https://ui.shadcn.com/schema.json", "style": "new-york", "rsc": false, "tsx": true, "tailwind": { "config": "tailwind.config.mjs", "css": "src/styles/globals.css", "baseColor": "slate", "cssVariables": true, "prefix": "" }, "aliases": { "components": "@/components", "utils": "@/lib/utils", "ui": "@/components/ui", "lib": "@/lib", "hooks": "@/hooks" }, "iconLibrary": "lucide" } ================================================ FILE: app/email-platform-schema.sql ================================================ -- 用户邮箱地址表 CREATE TABLE user_email_addresses ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 主键ID user_id TEXT NOT NULL, -- 关联的用户ID email_address TEXT NOT NULL, -- 邮箱地址 alias TEXT, -- 邮箱备注名 is_active INTEGER DEFAULT 1, -- 邮箱是否激活 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间 updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 更新时间 UNIQUE (email_address) ); CREATE INDEX idx_user_email_addresses_user_id ON user_email_addresses(user_id); -- 邮件主表 CREATE TABLE emails ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 主键ID message_id TEXT NOT NULL, -- 邮件唯一标识符 user_email_id INTEGER NOT NULL, -- 关联的用户邮箱ID subject TEXT, -- 邮件主题 sender TEXT NOT NULL, -- 发件人 recipient TEXT NOT NULL, -- 收件人 cc TEXT, -- 抄送人列表 bcc TEXT, -- 密送人列表 content_type TEXT, -- 内容类型 body_text TEXT, -- 纯文本内容 body_html TEXT, -- HTML格式内容 received_at DATETIME NOT NULL, -- 接收时间 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间 updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 更新时间 UNIQUE (message_id) ); CREATE INDEX idx_emails_user_email_id ON emails(user_email_id); CREATE INDEX idx_emails_received_at ON emails(received_at); -- 邮件状态表 CREATE TABLE email_status ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 主键ID email_id INTEGER NOT NULL, -- 关联的邮件ID user_id TEXT NOT NULL, -- 关联的用户ID is_read INTEGER DEFAULT 0, -- 是否已读 is_starred INTEGER DEFAULT 0, -- 是否标星 is_archived INTEGER DEFAULT 0, -- 是否归档 notes TEXT, -- 用户备注 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间 updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 更新时间 UNIQUE (email_id, user_id) ); CREATE INDEX idx_email_status_user_id ON email_status(user_id); -- 邮件标签表 CREATE TABLE email_tags ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 主键ID name TEXT NOT NULL, -- 标签名称 user_id TEXT NOT NULL, -- 关联的用户ID color TEXT, -- 标签颜色 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间 UNIQUE (name, user_id) ); -- 邮件-标签关联表 CREATE TABLE email_tag_relations ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 主键ID email_id INTEGER NOT NULL, -- 关联的邮件ID tag_id INTEGER NOT NULL, -- 关联的标签ID created_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间 UNIQUE (email_id, tag_id) ); CREATE INDEX idx_email_tag_relations_tag_id ON email_tag_relations(tag_id); ================================================ FILE: app/env.d.ts ================================================ /// type KVNamespace = import('@cloudflare/workers-types').KVNamespace; type D1Database = import('@cloudflare/workers-types').D1Database; type ENV = { POST_DB: KVNamespace; MAIL_DB: D1Database; DKIM_PRIVATE_KEY: string; PUBLIC_TURNSTILE_SITE_KEY: string; SECRET_KEY: string; PUBLIC_CLERK_PUBLISHABLE_KEY: string; CLERK_SECRET_KEY: string; PUBLIC_CLERK_SIGN_IN_URL: string; PUBLIC_CLERK_SIGN_UP_URL: string; }; // use a default runtime configuration (advanced mode). type Runtime = import('@astrojs/cloudflare').Runtime; declare namespace App { interface Locals extends Runtime {} } interface ImportMetaEnv { readonly SECRET_KEY: string; readonly PUBLIC_TURNSTILE_SITE_KEY: string; readonly PUBLIC_CLERK_PUBLISHABLE_KEY: string; readonly CLERK_SECRET_KEY: string; readonly PUBLIC_CLERK_SIGN_IN_URL: string; readonly PUBLIC_CLERK_SIGN_UP_URL: string; // 更多环境变量… } interface ImportMeta { readonly env: ImportMetaEnv; } ================================================ FILE: app/package.json ================================================ { "name": "app", "type": "module", "version": "0.0.1", "scripts": { "dev": "wrangler types && astro dev", "build": "astro build", "preview": "astro preview", "astro": "astro" }, "dependencies": { "@astrojs/cloudflare": "^12.1.0", "@astrojs/node": "^9.0.0", "@astrojs/react": "^4.1.2", "@astrojs/tailwind": "^5.1.4", "@clerk/astro": "^2.1.4", "@marsidev/react-turnstile": "^1.1.0", "@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-dialog": "^1.1.4", "@radix-ui/react-dropdown-menu": "^2.1.4", "@radix-ui/react-scroll-area": "^1.2.2", "@radix-ui/react-select": "^2.1.4", "@radix-ui/react-separator": "^1.1.1", "@radix-ui/react-slot": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.6", "@types/react": "^19.0.2", "@types/react-dom": "^19.0.2", "astro": "^5.1.2", "astro-seo": "^0.8.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "dayjs": "^1.11.13", "jotai": "^2.11.0", "lucide-react": "^0.469.0", "next-themes": "^0.4.4", "random-words": "^2.0.1", "react": "^19.0.0", "react-dom": "^19.0.0", "react-resizable-panels": "^2.1.7", "sonner": "^1.7.1", "tailwind-merge": "^2.6.0", "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7" }, "devDependencies": { "@cloudflare/workers-types": "^4.20241230.0", "wrangler": "^3.101.0" } } ================================================ FILE: app/public/robots.txt ================================================ User-agent: * Allow: / ================================================ FILE: app/src/components/Bar.astro ================================================ --- import { SignedIn, UserButton } from '@clerk/astro/components'; import { ModeToggle } from '@/components/ModeToggle'; ---
FakeMail

FakeMail

- Data is stored encrypted on cloudflare D1

================================================ FILE: app/src/components/Container.tsx ================================================ import { useState } from 'react'; import { Turnstile } from '@marsidev/react-turnstile'; import Lists from '@/components/Lists'; type Status = 'error' | 'expired' | 'solved'; const key = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY || '1x00000000000000000000AA'; export default ({ siteKey }: {siteKey?: string}) => { const [status, setStatus] = useState(null) if (status === 'solved' || import.meta.env.DEV) return return setStatus('error')} onExpire={() => setStatus('expired')} onSuccess={() => { setTimeout(() => { setStatus('solved'); }, 1000) }} /> }; ================================================ FILE: app/src/components/Footer.astro ================================================ --- import shoteasy from '@/assets/shoteasy.svg' import fakeact from '@/assets/fakeact.svg' ---
Copyright © 2025 FakeMail
================================================ FILE: app/src/components/Generator.tsx ================================================ import { useState } from 'react'; import { Copy, Check, RotateCw } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@/components/ui/tooltip'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog'; import { useCopyToClipboard } from '@/hooks/useCopyToClipboard'; import { useGeneratorMail } from '@/hooks/useGeneratorMail'; export default () => { const [address, generatorNewMail] = useGeneratorMail(); const [isCopy, setIsCopy] = useState(false); const [copiedText, copy] = useCopyToClipboard(); const [open, setOpen] = useState(false); const handleFocus = (event: any) => event.target.select(); const handleCopy = (text: string) => { if (isCopy) return; copy(text) .then(() => { setIsCopy(true); setTimeout(() => { setIsCopy(false); }, 1500); }) .catch((error) => { console.error('Failed to copy!', error); }); }; return (

Your fake email address

Copy to clipboard

Generate a new email address

Generate a new address? This will discard the current temporary address and create a new one. You will no longer receive mail at the old address. Cancel
); }; ================================================ FILE: app/src/components/Header.astro ================================================ --- import { LayoutDashboard } from 'lucide-react'; import Generator from '@/components/Generator'; import { ModeToggle } from '@/components/ModeToggle'; ---
Fakeact

FakeMail

Fake email generator,
delete emails 2 hours after receiving

Avoid spam, promo mail, and bots. Keep your real inbox clean and secure. FakeMail gives you temporary, anonymous, free disposable email addresses—no sign-up required to try.

Your temporary email address

================================================ FILE: app/src/components/Lists.tsx ================================================ import { useState, useEffect, useRef, memo } from 'react'; import { Inbox, Mails, RefreshCw, Loader2 } from 'lucide-react'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; import { MailCard } from '@/components/ui/mail-card'; import { Button } from '@/components/ui/button'; import { Toaster } from "@/components/ui/sonner"; import { toast } from "sonner" dayjs.extend(utc); const countDownTime = 30; const CountdownNumber = memo(({ value }: { value: number }) => ({value})); const CountDownComp = (({ value }: { value: number }) => { const [countDown, setCountDown] = useState(countDownTime); useEffect(() => { setCountDown(value); const intervalId = setInterval(() => { setCountDown((prevCount) => prevCount - 1); }, 1000); return () => { clearInterval(intervalId); }; }, [value]); return ( ); }); const MailCardComp = memo(({ mails, toDelete }: { mails: any[], toDelete: (mail: any) => void}) => mails.map((mail: any, index: number) => { if (mail) { return ( toDelete(mail)} /> ) } })); export default () => { const [mails, setMails] = useState([]); const [stats, setStats] = useState<{count: number}>({count: 0}); const [loading, setLoading] = useState(false); const intervalId = useRef(null); const countDownId = useRef(null); const intervalStop = useRef(0); const countDown = useRef(countDownTime); const fetchData = async () => { clearInterval(countDownId.current); if (intervalStop.current > 15) clearInterval(intervalId.current); try { const address = localStorage.getItem('receivingEmail'); if (!address) return; setLoading(true); const response = await fetch(`/api/get?address=${address}`); // Replace with your API endpoint if (!response.ok) { throw new Error('Network response was not ok.'); } countDown.current = countDownTime; countDownId.current = setInterval(() => { countDown.current = countDown.current - 1; }, 1000); intervalStop.current = intervalStop.current++; const data = await response.json(); if (data.mails && data.mails.length) { const arr = data.mails.filter((e: any) => e); arr.sort((a: any, b: any) => dayjs(b.date).unix() - dayjs(a.date).unix()); setMails(arr); if (arr.length) clearInterval(intervalId.current); } else { setMails([]); } if (Number(data.stats.count)) setStats({count: Number(data.stats.count)}); setLoading(false); } catch (error) { setLoading(false); } }; const refresh = () => { clearInterval(intervalId.current); intervalStop.current = 0; fetchData(); intervalId.current = setInterval(fetchData, countDownTime * 1000); } const toDelete = async (mail: any) => { const response = await fetch('/api/delete', { method: 'POST', body: JSON.stringify({ key: `${mail.recipient}-${mail.suffix}` }) }); // Replace with your API endpoint if (!response.ok) { throw new Error('Network response was not ok.'); } setMails(mails.filter((e: any) => e.suffix !== mail.suffix)); toast("The mail has been deleted!"); } useEffect(() => { fetchData(); intervalId.current = setInterval(fetchData, countDownTime * 1000); return () => { clearInterval(intervalId.current); }; }, []); const emptyDom = (

No email received yet

); return ( <>

Mail Inbox{mails.length ? `(${mails.length})` : ''}

{(intervalStop.current < 15 && !mails.length && !loading) &&
Refresh after s
}
{!mails.length ? emptyDom : }
-- We've received{stats.count.toLocaleString()}emails so far.
); }; ================================================ FILE: app/src/components/Main.astro ================================================ --- import Container from '@/components/Container'; const env = import.meta.env.PROD ? Astro.locals.runtime.env : import.meta.env; ---

What is the FakeMail?

FakeMail (Temporary email) — a free email service that lets you receive mail at a temporary address that self-destructs after a set time. It is also known as tempmail, 10minutemail, throwaway email, fake email generator, burner mail or trash mail. Many forums, Wi‑Fi networks, and sites ask for registration before you can view content, post, or download. FakeMail is a throwaway email service that helps you avoid spam and stay safe.

Why would you need a fake email address?

Services like Amazon Prime, Hulu, and Netflix offer limited-time trials; a disposable email address is one way to sign up. Some people use a different temporary address after a trial ends. Use responsibly and in line with each service’s terms.

Offline or online retailers often require an email address to access offers, which can lead to a flood of spam. A temporary email address makes it easy to avoid those unwanted messages.

While temporary email is sometimes associated with less legitimate use, there are many good reasons to use a disposable email service: trials, one-off signups, and keeping your real inbox clean.

Cloudflare temporary email

This temporary email service runs on Cloudflare Workers. You get a temporary address and can read received mail in your browser.

================================================ FILE: app/src/components/ModeToggle.tsx ================================================ import * as React from 'react'; import { Moon, Sun } from 'lucide-react'; import { Button } from '@/components/ui/button'; export function ModeToggle() { const [theme, setThemeState] = React.useState< 'theme-light' | 'dark' | 'system' >('theme-light'); React.useEffect(() => { const isDarkMode = document.documentElement.classList.contains('dark'); setThemeState(isDarkMode ? 'dark' : 'theme-light'); }, []); React.useEffect(() => { const isDark = theme === 'dark' || (theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches); document.documentElement.classList[isDark ? 'add' : 'remove']('dark'); }, [theme]); return ( ); } ================================================ FILE: app/src/components/mail/AccountSwitcher.tsx ================================================ import { useState } from 'react'; import { cn } from '@/lib/utils'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; interface AccountSwitcherProps { isCollapsed: boolean; accounts: { id: number; email_address: string; }[]; onAccountChange: (email: string) => void; } export function AccountSwitcher({ isCollapsed, accounts, onAccountChange }: AccountSwitcherProps) { const [selectedAccount, setSelectedAccount] = useState( accounts[0].email_address ); const handleChanged = (email: string) => { setSelectedAccount(email); onAccountChange(email); } return ( ); } ================================================ FILE: app/src/components/mail/Accounts.tsx ================================================ import { useRef, useState } from 'react'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Badge } from '@/components/ui/badge'; import { Textarea } from '@/components/ui/textarea'; import { Trash2, CirclePlus, FilePenLine, Loader2 } from "lucide-react"; import { Toaster } from "@/components/ui/sonner"; import { toast } from "sonner"; import type { AccountsList } from './data'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; dayjs.extend(utc); type AccountsProps = { list: AccountsList[] } export const Accounts = ({ list = [] }: AccountsProps) => { const remarkRef = useRef(null); const remarkEditRef = useRef(null); const [showDialog, setShowDialog] = useState(false); const [editAccount, setEditAccount] = useState(null); const [loading, setLoading] = useState(false); const toGenerate = async () => { const response = await fetch('/api/generate', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ remark: remarkRef.current?.value }), }); if (response.ok) { const data = await response.json(); if (data.code === 200) { return window.location.reload(); } toast.error(data.msg); } else { toast.error(response.statusText); } } const toSave = async () => { setLoading(true); const remark = (remarkEditRef.current?.value || '').trim(); const response = await fetch('/api/remarkMail', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: editAccount?.id, remark }), }); if (response.ok) { const data = await response.json(); if (data.code === 200) { list.forEach((account) => { if (account.id === editAccount?.id) { account.alias = remark; } }); setShowDialog(false); } toast.error(data.msg); } else { toast.error(response.statusText); } setLoading(false); } const toEdit = (account: AccountsList) => { setEditAccount(account); setShowDialog(true); } const onDialogChange = (e: boolean) => { setShowDialog(e); if (!e) { setEditAccount(null); } } return (
{list.map((account) => (
{account.email_address.substring(0, 1)}
{account.email_address}
{dayjs.utc(account.created_at).local().format('YYYY-MM-DD HH:mm:ss')}
{account.alias}
))}
Add a email address
Generate a random email address @fakeact.fun