diff --git a/.optimize-cache.json b/.optimize-cache.json index ecaeb30e0c0..7020fc85746 100644 --- a/.optimize-cache.json +++ b/.optimize-cache.json @@ -219,6 +219,7 @@ "static/images/blog/announcing-database-upsert/cover.png": "40839c8f5c28a5d78c2507f12e165ac8f176c53b81d8eb6b77b46d1c58f381dc", "static/images/blog/announcing-db-operators/cover.png": "9e0adb9ac1849e40b6a3c30ab4923ac63d1f551be1003ecb9804e4989bb2cf3c", "static/images/blog/announcing-deployment-retention/cover.png": "e6c59f73d83c1b88aed82a8974df97de83ab653241a5717f20b407809fa46ba9", + "static/images/blog/announcing-email-policies/cover.png": "3b62c98a38e16bbf4446624035e89e4ee2aba0af636c9ff32a0d2d5ab56d4e2c", "static/images/blog/announcing-encrypted-string-attributes/cover.png": "f3d1d0a022771392019c760c6dcf88fc231a7f96d19e2eb61d89b3605e818463", "static/images/blog/announcing-image-transformations-pricing/cover.png": "dfdd070a46b5f8c66d7b4781cc3dc61faa10c80307882e206be0ff7d46ca77db", "static/images/blog/announcing-image-transformations-pricing/usage-component.png": "e24a8b710ea5de5ee2fe7c2c4507f54dccb3530a602027fc7a4265d5fc7b6eca", @@ -1396,6 +1397,8 @@ "static/images/docs/ai/vector-db/search-demo.png": "c31ee2582814be34f2e563a595bbc48e58301d588fa3f8156d15bc6ecba222b7", "static/images/docs/assistant/ask-ai.png": "b2117420f13bc3fc370a925c47c949f7600adb9972e03c11d0e7d060a274c6fa", "static/images/docs/assistant/dark/ask-ai.png": "6f1a42c688a0bf0890ace1b563422c1273b704febe52c7554739619bc2802ea0", + "static/images/docs/auth/email-policies/dark/policies.png": "6d3a4e03452d34ee8e6bd036db58fb9ec6f3a1a6d76bb932fb29ebef49be0145", + "static/images/docs/auth/email-policies/policies.png": "37e26e5f14d275978e1ca818f46d0daf2a6c56bf15255161ae4c2ac1ac55d5a5", "static/images/docs/auth/ssr/dark/ssr.png": "3b80b80e061ada103e4f8e4bdf3c0a554db062aaed3f5f3a6b02f5f9c05859fa", "static/images/docs/auth/ssr/ssr.png": "a9a58a3a053dbfec7eef50894d973049254ac9af4ed7159f93a5dd95dc0faf94", "static/images/docs/command-center/command-center.png": "4e32c190ab1fbc74040c43b2d85a8404af9b553bb9672c1a842fee92ecd48b31", diff --git a/src/routes/blog/post/announcing-email-policies/+page.markdoc b/src/routes/blog/post/announcing-email-policies/+page.markdoc new file mode 100644 index 00000000000..d5f756abf12 --- /dev/null +++ b/src/routes/blog/post/announcing-email-policies/+page.markdoc @@ -0,0 +1,262 @@ +--- +layout: post +title: "Announcing Email policies: Block free, aliased, and disposable emails at signup" +description: Email policies let you restrict which email addresses can sign up for your Appwrite project. Block free providers, aliased addresses, and disposable inboxes from the Console or any server SDK. +date: 2026-05-20 +cover: /images/blog/announcing-email-policies/cover.avif +timeToRead: 4 +author: matej-baco +category: announcement +featured: false +callToAction: true +faqs: + - question: "Do email policies affect users who signed up before the policy was enabled?" + answer: "No. Email policies only run at sign-up and on email updates. Existing users can still log in with their current address even if that address would no longer pass the policy." + - question: "What scope does an API key need to update email policies?" + answer: "The API key needs the policies.write scope. Reading the current policy state requires policies.read." + - question: "Does the aliased emails policy cover providers other than Gmail?" + answer: "Yes. The policy blocks subaddresses, tags, and provider-specific variations across providers, not just Gmail. Anything that maps to the same underlying inbox via well-known alias syntax is rejected." + - question: "Can I enable just one of the three email policies instead of all of them?" + answer: "Yes. Each policy is an independent toggle. You can enable any combination of deny free, deny aliased, and deny disposable from the Console or by calling only the methods you need." + - question: "How do I fight spam users?" + answer: "Email policies are the first line of defense. Enable deny disposable emails to block temporary inboxes like Mailinator, deny aliased emails to stop one user from spinning up dozens of accounts from a single Gmail with subaddresses, and deny free emails on B2B products that should only accept corporate addresses." + - question: "Which email providers does Appwrite block?" + answer: "The lists are powered by our open-source utopia-php/emails database, which currently tracks over 72,000 disposable domains and 4,000 free email providers. The data is continuously refreshed from six upstream community sources, with a manual override layer on top for edge cases the upstream lists miss." + - question: "Can I add a missing email provider to the blocklist?" + answer: "Yes. The utopia-php/emails repository is open source and accepts contributions. Open a PR against the manual list in the data directory and the next import picks it up." +--- + +Most teams discover the hard way that signups happen with whatever address a user feels like typing. Throwaway inboxes, plus-tagged aliases of a single Gmail, and ten-minute mail providers all create real accounts, count toward seat quotas, and eventually show up in your support queue with mail that never delivers. + +Today, we are announcing **Email policies** for Appwrite Auth. You can now restrict which email addresses are accepted for user creation and email updates on a project, either from the Appwrite Console or programmatically through any server SDK. + +# What you can block + +Email policies expose three independent toggles, each targeting a different category of address: + +- **Free email providers** like Gmail, Yahoo, and Outlook, so trials and seats stay tied to a real organization +- **Aliased addresses** such as subaddresses, tags, and provider-specific variations of the same inbox, so one user cannot quietly create twenty accounts from one mailbox +- **Disposable providers** like Mailinator and other temporary inbox services, so abandoned accounts and undeliverable mail stop landing in your users table + +Each policy is its own toggle. Enabling one does not enable the others, so a B2B product can require corporate addresses without also blocking disposable ones, and a consumer product can keep free providers open while shutting out throwaway inboxes. + +The policies run at signup and on email updates. They do not affect session creation, so any user who signed up before a policy was enabled can still log in. + +# Backed by a curated provider database + +Email policies do not ship with a hard-coded list of a few dozen well-known providers. They are powered by [utopia-php/emails](https://github.com/utopia-php/emails), an open-source database we maintain that currently tracks **72,906 disposable domains** and **4,785 free email providers**. The lists are continuously refreshed from six upstream community sources, on top of a manual override layer for edge cases that the upstream lists miss or get wrong. + +The data lives in the open and accepts contributions, so if you spot a provider that should be blocked or unblocked you can [open a PR against the manual list](https://github.com/utopia-php/emails/tree/main/data) and the next import picks it up. + +# Configure from the Console + +Open your project, navigate to **Auth** in the sidebar, and open the **Security** tab. The **Email policies** card has a toggle for each policy and an **Update** button that applies your changes immediately. + +![Email policies card in the Appwrite Console](/images/docs/auth/email-policies/dark/policies.avif) + +# Configure from the SDK + +Each policy has a dedicated method on the Project service. The body is always an `enabled` boolean. + +The API key needs the `policies.write` scope. + +{% multicode %} +```server-nodejs +import { Client, Project } from 'node-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +const project = new Project(client); + +await project.updateDenyFreeEmailPolicy({ enabled: true }); +await project.updateDenyAliasedEmailPolicy({ enabled: true }); +await project.updateDenyDisposableEmailPolicy({ enabled: true }); +``` +```server-deno +import { Client, Project } from "npm:node-appwrite"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +const project = new Project(client); + +await project.updateDenyFreeEmailPolicy({ enabled: true }); +await project.updateDenyAliasedEmailPolicy({ enabled: true }); +await project.updateDenyDisposableEmailPolicy({ enabled: true }); +``` +```server-php +setEndpoint('https://.cloud.appwrite.io/v1') + ->setProject('') + ->setKey(''); + +$project = new Project($client); + +$project->updateDenyFreeEmailPolicy(enabled: true); +$project->updateDenyAliasedEmailPolicy(enabled: true); +$project->updateDenyDisposableEmailPolicy(enabled: true); +``` +```server-python +from appwrite.client import Client +from appwrite.services.project import Project + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') +client.set_project('') +client.set_key('') + +project = Project(client) + +project.update_deny_free_email_policy(enabled=True) +project.update_deny_aliased_email_policy(enabled=True) +project.update_deny_disposable_email_policy(enabled=True) +``` +```server-ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') + .set_project('') + .set_key('') + +project = Project.new(client) + +project.update_deny_free_email_policy(enabled: true) +project.update_deny_aliased_email_policy(enabled: true) +project.update_deny_disposable_email_policy(enabled: true) +``` +```server-dotnet +using Appwrite; +using Appwrite.Services; + +Client client = new Client() + .SetEndPoint("https://.cloud.appwrite.io/v1") + .SetProject("") + .SetKey(""); + +Project project = new Project(client); + +await project.UpdateDenyFreeEmailPolicy(enabled: true); +await project.UpdateDenyAliasedEmailPolicy(enabled: true); +await project.UpdateDenyDisposableEmailPolicy(enabled: true); +``` +```server-dart +import 'package:dart_appwrite/dart_appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +Project project = Project(client); + +await project.updateDenyFreeEmailPolicy(enabled: true); +await project.updateDenyAliasedEmailPolicy(enabled: true); +await project.updateDenyDisposableEmailPolicy(enabled: true); +``` +```server-kotlin +import io.appwrite.Client +import io.appwrite.services.Project + +val client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey("") + +val project = Project(client) + +project.updateDenyFreeEmailPolicy(enabled = true) +project.updateDenyAliasedEmailPolicy(enabled = true) +project.updateDenyDisposableEmailPolicy(enabled = true) +``` +```server-swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey("") + +let project = Project(client) + +_ = try await project.updateDenyFreeEmailPolicy(enabled: true) +_ = try await project.updateDenyAliasedEmailPolicy(enabled: true) +_ = try await project.updateDenyDisposableEmailPolicy(enabled: true) +``` +```server-go +package main + +import ( + "github.com/appwrite/sdk-for-go/appwrite" +) + +func main() { + client := appwrite.NewClient( + appwrite.WithEndpoint("https://.cloud.appwrite.io/v1"), + appwrite.WithProject(""), + appwrite.WithKey(""), + ) + + service := appwrite.NewProject(client) + + if _, err := service.UpdateDenyFreeEmailPolicy(true); err != nil { + panic(err) + } + if _, err := service.UpdateDenyAliasedEmailPolicy(true); err != nil { + panic(err) + } + if _, err := service.UpdateDenyDisposableEmailPolicy(true); err != nil { + panic(err) + } +} +``` +```server-rust +use appwrite::Client; +use appwrite::services::project::Project; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new() + .set_endpoint("https://.cloud.appwrite.io/v1") + .set_project("") + .set_key(""); + + let project = Project::new(&client); + + project.update_deny_free_email_policy(true).await?; + project.update_deny_aliased_email_policy(true).await?; + project.update_deny_disposable_email_policy(true).await?; + + Ok(()) +} +``` +```bash +appwrite project update-deny-free-email-policy --enabled true +appwrite project update-deny-canonical-email-policy --enabled true +appwrite project update-deny-disposable-email-policy --enabled true +``` +{% /multicode %} + +# Get started + +Email policies are available now on Appwrite Cloud. Head to **Auth > Security** in the Console, or read the [Email policies documentation](/docs/products/auth/email-policies) for the full SDK reference and per-language examples. + +# Resources + +- [Email policies documentation](/docs/products/auth/email-policies) +- [Auth security guide](/docs/products/auth/security) +- [Join the Appwrite Discord community](https://appwrite.io/discord) diff --git a/src/routes/changelog/(entries)/2026-05-20.markdoc b/src/routes/changelog/(entries)/2026-05-20.markdoc new file mode 100644 index 00000000000..4e8ab211c0a --- /dev/null +++ b/src/routes/changelog/(entries)/2026-05-20.markdoc @@ -0,0 +1,20 @@ +--- +layout: changelog +title: "Announcing Email policies for Appwrite Auth" +date: 2026-05-20 +cover: /images/blog/announcing-email-policies/cover.avif +--- + +Appwrite Auth now supports [**Email policies**](/docs/products/auth/email-policies), letting you restrict which email addresses can be used for user creation and email updates on a project. Three independent toggles cover the most common signup hygiene problems: free providers like Gmail and Yahoo, aliased addresses such as subaddresses and provider-specific variations of one inbox, and disposable providers like Mailinator. + +Each policy is its own toggle, so a B2B product can require corporate addresses without also blocking disposable ones, and a consumer product can keep free providers open while shutting out throwaway inboxes. The policies run at signup and on email updates only. Existing users keep their sessions and can still log in. + +Configure email policies from the Console under **Auth > Security**, or through any server SDK using the Project service. + +{% arrow_link href="/blog/post/announcing-email-policies" %} +Read the announcement +{% /arrow_link %} + +{% arrow_link href="/docs/products/auth/email-policies" %} +Email policies in the docs +{% /arrow_link %} diff --git a/src/routes/docs/products/auth/+layout.svelte b/src/routes/docs/products/auth/+layout.svelte index 418e2a3793a..799c2019496 100644 --- a/src/routes/docs/products/auth/+layout.svelte +++ b/src/routes/docs/products/auth/+layout.svelte @@ -54,6 +54,11 @@ label: 'Security', href: '/docs/products/auth/security' }, + { + label: 'Email policies', + href: '/docs/products/auth/email-policies', + new: isNewUntil('30 June 2026') + }, { label: 'Tokens', href: '/docs/products/auth/tokens' diff --git a/src/routes/docs/products/auth/email-policies/+page.markdoc b/src/routes/docs/products/auth/email-policies/+page.markdoc new file mode 100644 index 00000000000..30fd7eeb85e --- /dev/null +++ b/src/routes/docs/products/auth/email-policies/+page.markdoc @@ -0,0 +1,690 @@ +--- +layout: article +title: Email policies +description: Control which email addresses can sign up for your Appwrite project by blocking free, aliased, or disposable email providers from the Console or Project API. +--- + +Email policies let you restrict which email addresses can be used for user creation and email updates on a project. Each policy is an independent toggle that runs at sign-up time and when an existing user changes their email. Policies do not affect session creation, so existing users can still sign in if their address would not pass the current policy. + +Three policies are available: + +| Policy | Blocks | Example | +| --- | --- | --- | +| Deny free emails | Addresses from free email providers | `user@gmail.com` | +| Deny aliased emails | Addresses with aliases, tags, subaddresses, or any provider-specific variation | `user+folder1@gmail.com` | +| Deny disposable emails | Temporary and disposable email providers | `alex9734@mailinator.com` | + +Policies can be configured from the Appwrite Console or programmatically through any server SDK using the Project service. + +# Manage from the Console {% #manage-console %} + +{% only_dark %} +![Email policies card in the Appwrite Console](/images/docs/auth/email-policies/dark/policies.avif) +{% /only_dark %} +{% only_light %} +![Email policies card in the Appwrite Console](/images/docs/auth/email-policies/policies.avif) +{% /only_light %} + +To configure email policies manually: + +1. Open your project in the Appwrite Console. +2. Navigate to **Auth** in the sidebar. +3. Open the **Security** tab. +4. In the **Email policies** card, toggle the policies you want to enable. +5. Click **Update** to apply the changes. + +# Manage from the SDK {% #manage-sdk %} + +Each policy has its own method on the Project service. The body is always an `enabled` boolean. + +{% info title="Required scope" %} +The API key used for these calls needs the `policies.write` scope. +{% /info %} + +## Deny free emails {% #deny-free-emails %} + +When enabled, sign-ups and email updates using addresses from free email providers such as Gmail or Yahoo are rejected. + +{% multicode %} +```server-nodejs +import { Client, Project } from 'node-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +const project = new Project(client); + +const result = await project.updateDenyFreeEmailPolicy({ + enabled: true +}); +``` +```server-deno +import { Client, Project } from "npm:node-appwrite"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +const project = new Project(client); + +const result = await project.updateDenyFreeEmailPolicy({ + enabled: true +}); +``` +```server-php +setEndpoint('https://.cloud.appwrite.io/v1') + ->setProject('') + ->setKey(''); + +$project = new Project($client); + +$result = $project->updateDenyFreeEmailPolicy( + enabled: true +); +``` +```server-python +from appwrite.client import Client +from appwrite.services.project import Project + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') +client.set_project('') +client.set_key('') + +project = Project(client) + +result = project.update_deny_free_email_policy( + enabled = True +) +``` +```server-ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') + .set_project('') + .set_key('') + +project = Project.new(client) + +response = project.update_deny_free_email_policy( + enabled: true +) +``` +```server-dotnet +using Appwrite; +using Appwrite.Services; + +Client client = new Client() + .SetEndPoint("https://.cloud.appwrite.io/v1") + .SetProject("") + .SetKey(""); + +Project project = new Project(client); + +var result = await project.UpdateDenyFreeEmailPolicy( + enabled: true +); +``` +```server-dart +import 'package:dart_appwrite/dart_appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +Project project = Project(client); + +final result = await project.updateDenyFreeEmailPolicy( + enabled: true, +); +``` +```server-kotlin +import io.appwrite.Client +import io.appwrite.services.Project + +val client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey("") + +val project = Project(client) + +val response = project.updateDenyFreeEmailPolicy( + enabled = true +) +``` +```server-java +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Project; + +Client client = new Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey(""); + +Project project = new Project(client); + +project.updateDenyFreeEmailPolicy( + true, // enabled + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + System.out.println(result); + }) +); +``` +```server-swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey("") + +let project = Project(client) + +let result = try await project.updateDenyFreeEmailPolicy( + enabled: true +) +``` +```server-go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/appwrite" +) + +func main() { + client := appwrite.NewClient( + appwrite.WithEndpoint("https://.cloud.appwrite.io/v1"), + appwrite.WithProject(""), + appwrite.WithKey(""), + ) + + service := appwrite.NewProject(client) + result, err := service.UpdateDenyFreeEmailPolicy(true) + + if err != nil { + panic(err) + } + + fmt.Println(result) +} +``` +```server-rust +use appwrite::Client; +use appwrite::services::project::Project; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new() + .set_endpoint("https://.cloud.appwrite.io/v1") + .set_project("") + .set_key(""); + + let project = Project::new(&client); + + let result = project.update_deny_free_email_policy(true).await?; + + println!("{:?}", result); + Ok(()) +} +``` +```bash +appwrite project update-deny-free-email-policy --enabled true +``` +{% /multicode %} + +## Deny aliased emails {% #deny-aliased-emails %} + +When enabled, sign-ups and email updates using addresses with aliases, tags, subaddresses, or any other provider-specific variation are rejected. + +{% multicode %} +```server-nodejs +import { Client, Project } from 'node-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +const project = new Project(client); + +const result = await project.updateDenyAliasedEmailPolicy({ + enabled: true +}); +``` +```server-deno +import { Client, Project } from "npm:node-appwrite"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +const project = new Project(client); + +const result = await project.updateDenyAliasedEmailPolicy({ + enabled: true +}); +``` +```server-php +setEndpoint('https://.cloud.appwrite.io/v1') + ->setProject('') + ->setKey(''); + +$project = new Project($client); + +$result = $project->updateDenyAliasedEmailPolicy( + enabled: true +); +``` +```server-python +from appwrite.client import Client +from appwrite.services.project import Project + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') +client.set_project('') +client.set_key('') + +project = Project(client) + +result = project.update_deny_aliased_email_policy( + enabled = True +) +``` +```server-ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') + .set_project('') + .set_key('') + +project = Project.new(client) + +response = project.update_deny_aliased_email_policy( + enabled: true +) +``` +```server-dotnet +using Appwrite; +using Appwrite.Services; + +Client client = new Client() + .SetEndPoint("https://.cloud.appwrite.io/v1") + .SetProject("") + .SetKey(""); + +Project project = new Project(client); + +var result = await project.UpdateDenyAliasedEmailPolicy( + enabled: true +); +``` +```server-dart +import 'package:dart_appwrite/dart_appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +Project project = Project(client); + +final result = await project.updateDenyAliasedEmailPolicy( + enabled: true, +); +``` +```server-kotlin +import io.appwrite.Client +import io.appwrite.services.Project + +val client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey("") + +val project = Project(client) + +val response = project.updateDenyAliasedEmailPolicy( + enabled = true +) +``` +```server-java +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Project; + +Client client = new Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey(""); + +Project project = new Project(client); + +project.updateDenyAliasedEmailPolicy( + true, // enabled + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + System.out.println(result); + }) +); +``` +```server-swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey("") + +let project = Project(client) + +let result = try await project.updateDenyAliasedEmailPolicy( + enabled: true +) +``` +```server-go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/appwrite" +) + +func main() { + client := appwrite.NewClient( + appwrite.WithEndpoint("https://.cloud.appwrite.io/v1"), + appwrite.WithProject(""), + appwrite.WithKey(""), + ) + + service := appwrite.NewProject(client) + result, err := service.UpdateDenyAliasedEmailPolicy(true) + + if err != nil { + panic(err) + } + + fmt.Println(result) +} +``` +```server-rust +use appwrite::Client; +use appwrite::services::project::Project; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new() + .set_endpoint("https://.cloud.appwrite.io/v1") + .set_project("") + .set_key(""); + + let project = Project::new(&client); + + let result = project.update_deny_aliased_email_policy(true).await?; + + println!("{:?}", result); + Ok(()) +} +``` +```bash +appwrite project update-deny-canonical-email-policy --enabled true +``` +{% /multicode %} + +## Deny disposable emails {% #deny-disposable-emails %} + +When enabled, sign-ups and email updates using addresses from known temporary or disposable providers are rejected. + +{% multicode %} +```server-nodejs +import { Client, Project } from 'node-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +const project = new Project(client); + +const result = await project.updateDenyDisposableEmailPolicy({ + enabled: true +}); +``` +```server-deno +import { Client, Project } from "npm:node-appwrite"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +const project = new Project(client); + +const result = await project.updateDenyDisposableEmailPolicy({ + enabled: true +}); +``` +```server-php +setEndpoint('https://.cloud.appwrite.io/v1') + ->setProject('') + ->setKey(''); + +$project = new Project($client); + +$result = $project->updateDenyDisposableEmailPolicy( + enabled: true +); +``` +```server-python +from appwrite.client import Client +from appwrite.services.project import Project + +client = Client() +client.set_endpoint('https://.cloud.appwrite.io/v1') +client.set_project('') +client.set_key('') + +project = Project(client) + +result = project.update_deny_disposable_email_policy( + enabled = True +) +``` +```server-ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') + .set_project('') + .set_key('') + +project = Project.new(client) + +response = project.update_deny_disposable_email_policy( + enabled: true +) +``` +```server-dotnet +using Appwrite; +using Appwrite.Services; + +Client client = new Client() + .SetEndPoint("https://.cloud.appwrite.io/v1") + .SetProject("") + .SetKey(""); + +Project project = new Project(client); + +var result = await project.UpdateDenyDisposableEmailPolicy( + enabled: true +); +``` +```server-dart +import 'package:dart_appwrite/dart_appwrite.dart'; + +Client client = Client() + .setEndpoint('https://.cloud.appwrite.io/v1') + .setProject('') + .setKey(''); + +Project project = Project(client); + +final result = await project.updateDenyDisposableEmailPolicy( + enabled: true, +); +``` +```server-kotlin +import io.appwrite.Client +import io.appwrite.services.Project + +val client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey("") + +val project = Project(client) + +val response = project.updateDenyDisposableEmailPolicy( + enabled = true +) +``` +```server-java +import io.appwrite.Client; +import io.appwrite.coroutines.CoroutineCallback; +import io.appwrite.services.Project; + +Client client = new Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey(""); + +Project project = new Project(client); + +project.updateDenyDisposableEmailPolicy( + true, // enabled + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + System.out.println(result); + }) +); +``` +```server-swift +import Appwrite + +let client = Client() + .setEndpoint("https://.cloud.appwrite.io/v1") + .setProject("") + .setKey("") + +let project = Project(client) + +let result = try await project.updateDenyDisposableEmailPolicy( + enabled: true +) +``` +```server-go +package main + +import ( + "fmt" + "github.com/appwrite/sdk-for-go/appwrite" +) + +func main() { + client := appwrite.NewClient( + appwrite.WithEndpoint("https://.cloud.appwrite.io/v1"), + appwrite.WithProject(""), + appwrite.WithKey(""), + ) + + service := appwrite.NewProject(client) + result, err := service.UpdateDenyDisposableEmailPolicy(true) + + if err != nil { + panic(err) + } + + fmt.Println(result) +} +``` +```server-rust +use appwrite::Client; +use appwrite::services::project::Project; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let client = Client::new() + .set_endpoint("https://.cloud.appwrite.io/v1") + .set_project("") + .set_key(""); + + let project = Project::new(&client); + + let result = project.update_deny_disposable_email_policy(true).await?; + + println!("{:?}", result); + Ok(()) +} +``` +```bash +appwrite project update-deny-disposable-email-policy --enabled true +``` +{% /multicode %} + +# Benefits {% #benefits %} + +Enabling email policies on your project provides: + +- **Higher quality user data**: Block low-effort or throw-away addresses so the accounts that do sign up represent real users you can reach later +- **Lower spam and abuse**: Cut down on bot signups, trial abuse, and duplicate accounts created with subaddresses of the same inbox +- **Stronger business rules**: Enforce work-email-only access on products that aren't meant for personal Gmail or Yahoo accounts +- **Less downstream cleanup**: Reduce the bounced emails, unreachable users, and support tickets that come from invalid addresses making it into your database diff --git a/static/images/blog/announcing-email-policies/cover.avif b/static/images/blog/announcing-email-policies/cover.avif new file mode 100644 index 00000000000..de6a2c33a72 Binary files /dev/null and b/static/images/blog/announcing-email-policies/cover.avif differ diff --git a/static/images/docs/auth/email-policies/dark/policies.avif b/static/images/docs/auth/email-policies/dark/policies.avif new file mode 100644 index 00000000000..310aa010594 Binary files /dev/null and b/static/images/docs/auth/email-policies/dark/policies.avif differ diff --git a/static/images/docs/auth/email-policies/policies.avif b/static/images/docs/auth/email-policies/policies.avif new file mode 100644 index 00000000000..5263460b65d Binary files /dev/null and b/static/images/docs/auth/email-policies/policies.avif differ