EmailVerify LogoEmailVerify

Shopify

Email checker for Shopify. Verify customer emails at checkout and in Shopify apps.

Protect your Shopify store from fake accounts, reduce cart abandonment email bounces, and improve customer communication by verifying email addresses.

Why Verify Emails in Shopify?

ChallengeImpactSolution
Fake accountsPromo abuse, fraudVerify at registration
Cart abandonmentBounced recovery emailsVerify before sending
Order notificationsFailed delivery updatesVerify at checkout
Marketing campaignsLow deliverabilityClean customer list

Integration Methods

MethodBest ForComplexity
Shopify FlowAutomated workflowsLow
Shopify FunctionsCheckout validationMedium
Third-party AppFull solutionLow
Custom AppComplete controlHigh

Use Shopify Flow to verify emails automatically.

Verify New Customer Emails

Create a workflow to verify emails when customers register:

Trigger: Customer created

Condition: Customer email is not blank

Actions:

  1. Send HTTP request to EmailVerify
  2. Add customer tag based on result

Flow Configuration

Workflow: Verify New Customer Email

Trigger:
  Event: Customer created

Condition:
  - Customer email is not blank

Action 1:
  Type: Send HTTP request
  URL: https://api.emailverify.ai/v1/verify
  Method: POST
  Headers:
    - Authorization: Bearer YOUR_API_KEY
    - Content-Type: application/json
  Body: {"email": "{{customer.email}}"}

Wait:
  Duration: 1 second

Action 2:
  Type: Add customer tags
  Tags:
    - email_verified (if status = valid)
    - email_invalid (if status = invalid)

Verify Before Cart Abandonment Emails

Workflow: Verify Before Abandonment Email

Trigger:
  Event: Checkout abandoned
  Delay: 1 hour

Condition:
  - Customer email is not blank
  - Customer does not have tag "email_invalid"

Action 1:
  Type: Send HTTP request to EmailVerify
  Body: {"email": "{{checkout.email}}"}

Action 2:
  Type: Branch
  If status = "valid":
    - Continue to abandonment email sequence
  If status = "invalid":
    - Add tag "email_invalid"
    - Do not send email

Method 2: Checkout Validation with Shopify Functions

Create a Shopify Function to validate emails during checkout.

Step 1: Create a Cart Transform Function

// extensions/email-validation/src/run.js
import { EmailVerify } from '@emailverify/node';

export function run(input) {
  const { cart } = input;
  const email = cart?.buyerIdentity?.email;

  if (!email) {
    return { operations: [] };
  }

  // Note: For real-time validation, use a pre-validated cache
  // or implement async validation via metafield
  return {
    operations: [],
  };
}

Step 2: Create a Checkout UI Extension

// extensions/email-validation-ui/src/Checkout.jsx
import {
  useExtensionApi,
  render,
  Banner,
  BlockStack,
} from '@shopify/checkout-ui-extensions-react';
import { useState, useEffect } from 'react';

render('Checkout::Contact::RenderAfter', () => <EmailValidation />);

function EmailValidation() {
  const { buyerIdentity } = useExtensionApi();
  const [validationStatus, setValidationStatus] = useState(null);

  useEffect(() => {
    const email = buyerIdentity?.email?.current;
    if (email) {
      validateEmail(email).then(setValidationStatus);
    }
  }, [buyerIdentity?.email?.current]);

  if (!validationStatus) return null;

  if (validationStatus.status === 'invalid') {
    return (
      <Banner status="warning">
        Please check your email address. It appears to be invalid.
      </Banner>
    );
  }

  if (validationStatus.result?.disposable) {
    return (
      <Banner status="info">
        We recommend using a permanent email for order updates.
      </Banner>
    );
  }

  return null;
}

async function validateEmail(email) {
  const response = await fetch('/apps/email-verify/validate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email }),
  });
  return response.json();
}

Method 3: Custom Shopify App

Build a complete email verification solution.

App Backend (Node.js)

// server/index.js
import '@shopify/shopify-app-remix/adapters/node';
import { shopifyApp } from '@shopify/shopify-app-remix/server';
import { EmailVerify } from '@emailverify/node';

const shopify = shopifyApp({
  // ... Shopify config
});

const emailVerify = new EmailVerify({
  apiKey: process.env.EMAILVERIFY_API_KEY,
});

// API route for email verification
export async function action({ request }) {
  const { email, customerId } = await request.json();

  try {
    const result = await emailVerify.verify(email);

    // Update customer metafield
    if (customerId) {
      await updateCustomerVerificationStatus(customerId, result);
    }

    return json(result);
  } catch (error) {
    return json({ error: error.message }, { status: 500 });
  }
}

async function updateCustomerVerificationStatus(customerId, result) {
  const { admin } = await shopify.authenticate.admin(request);

  await admin.graphql(`
    mutation updateCustomerMetafield($input: CustomerInput!) {
      customerUpdate(input: $input) {
        customer {
          id
        }
      }
    }
  `, {
    variables: {
      input: {
        id: `gid://shopify/Customer/${customerId}`,
        metafields: [
          {
            namespace: "email_verification",
            key: "status",
            value: result.status,
            type: "single_line_text_field"
          },
          {
            namespace: "email_verification",
            key: "score",
            value: String(result.score),
            type: "number_decimal"
          },
          {
            namespace: "email_verification",
            key: "verified_at",
            value: new Date().toISOString(),
            type: "date_time"
          }
        ]
      }
    }
  });
}

Webhook Handler

Handle customer creation webhooks:

// server/webhooks/customer-created.js
export async function handleCustomerCreated(topic, shop, body) {
  const customer = JSON.parse(body);
  const { id, email } = customer;

  if (!email) return;

  try {
    // Verify email
    const result = await emailVerify.verify(email);

    // Update customer with tags
    const tags = [];
    if (result.status === 'valid') {
      tags.push('email_verified');
    } else if (result.status === 'invalid') {
      tags.push('email_invalid');
    }
    if (result.result?.disposable) {
      tags.push('disposable_email');
    }

    await updateCustomerTags(shop, id, tags);

    // Store verification result
    await updateCustomerVerificationStatus(shop, id, result);

    console.log(`Verified ${email}: ${result.status}`);
  } catch (error) {
    console.error(`Failed to verify ${email}:`, error);
  }
}

Theme Integration (Liquid)

Add verification to registration form:

{% comment %} snippets/email-verification.liquid {% endcomment %}

<script>
document.addEventListener('DOMContentLoaded', function() {
  const emailInput = document.querySelector('input[type="email"]');
  const submitButton = document.querySelector('form[action="/account"] button[type="submit"]');

  let verificationResult = null;

  emailInput.addEventListener('blur', async function() {
    const email = this.value;
    if (!email) return;

    // Show loading state
    emailInput.classList.add('verifying');

    try {
      const response = await fetch('/apps/emailverify/verify', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email })
      });

      verificationResult = await response.json();

      // Update UI based on result
      updateEmailFieldUI(verificationResult);
    } catch (error) {
      console.error('Verification failed:', error);
    } finally {
      emailInput.classList.remove('verifying');
    }
  });

  function updateEmailFieldUI(result) {
    // Remove existing messages
    const existingMessage = document.querySelector('.email-verification-message');
    if (existingMessage) existingMessage.remove();

    // Create message element
    const message = document.createElement('div');
    message.className = 'email-verification-message';

    if (result.status === 'invalid') {
      message.classList.add('error');
      message.textContent = 'Please enter a valid email address';
      submitButton.disabled = true;
    } else if (result.result?.disposable) {
      message.classList.add('warning');
      message.textContent = 'Please use a permanent email for account recovery';
    } else if (result.status === 'valid') {
      message.classList.add('success');
      message.textContent = '✓ Email verified';
      submitButton.disabled = false;
    }

    emailInput.parentNode.appendChild(message);
  }
});
</script>

<style>
.email-verification-message {
  font-size: 12px;
  margin-top: 4px;
}
.email-verification-message.error { color: #c9302c; }
.email-verification-message.warning { color: #f0ad4e; }
.email-verification-message.success { color: #5cb85c; }
input[type="email"].verifying {
  background-image: url('/path/to/spinner.gif');
  background-position: right 10px center;
  background-repeat: no-repeat;
}
</style>

Use Cases

1. Prevent Fake Account Registration

Block disposable and invalid emails during signup:

// Theme app extension
async function validateRegistration(email) {
  const result = await verifyEmail(email);

  if (result.status === 'invalid') {
    return {
      valid: false,
      message: 'Please enter a valid email address',
    };
  }

  if (result.result.disposable) {
    return {
      valid: false,
      message: 'Temporary email addresses are not allowed',
    };
  }

  return { valid: true };
}

2. Cart Abandonment Recovery

Only send abandonment emails to valid addresses:

Shopify Flow:
  Trigger: Checkout abandoned (1 hour delay)

  Condition: Check email verification status

  If valid:
    → Send abandonment email
    → Add to remarketing audience

  If invalid:
    → Skip email
    → Log for analytics

3. Order Risk Assessment

Factor email quality into fraud detection:

function calculateOrderRiskScore(order, emailVerification) {
  let riskScore = 0;

  // Email verification factors
  if (emailVerification.status === 'invalid') {
    riskScore += 30;
  }

  if (emailVerification.result?.disposable) {
    riskScore += 20;
  }

  if (emailVerification.result?.free && order.total > 500) {
    riskScore += 10; // High value order with free email
  }

  // Other factors...
  if (order.billing_address !== order.shipping_address) {
    riskScore += 15;
  }

  return riskScore;
}

4. Customer Segmentation

Create customer segments based on email quality:

SegmentCriteriaMarketing Strategy
High ValueVerified, business emailPremium campaigns
StandardVerified, free emailRegular campaigns
At RiskUnverified, old accountRe-verification campaign
ExcludedInvalid, disposableNo marketing

Metafield Setup

Create metafields to store verification data:

Customer Metafields

mutation createMetafieldDefinitions {
  metafieldDefinitionCreate(definition: {
    namespace: "email_verification"
    key: "status"
    name: "Email Verification Status"
    type: "single_line_text_field"
    ownerType: CUSTOMER
  }) {
    createdDefinition { id }
  }
}

Recommended metafields:

NamespaceKeyTypeDescription
email_verificationstatussingle_line_text_fieldvalid, invalid, unknown
email_verificationscorenumber_decimal0.0 - 1.0
email_verificationverified_atdate_timeLast verification date
email_verificationdisposablebooleanIs disposable email
email_verificationrole_basedbooleanIs role-based email

Access Metafields in Liquid

{% if customer.metafields.email_verification.status == 'valid' %}
  <span class="verified-badge">✓ Verified</span>
{% endif %}

Bulk Customer Verification

Clean your existing customer list:

Export Customers

async function exportCustomersForVerification(admin) {
  const query = `
    query getCustomers($cursor: String) {
      customers(first: 250, after: $cursor) {
        edges {
          node {
            id
            email
            createdAt
            metafield(namespace: "email_verification", key: "status") {
              value
            }
          }
          cursor
        }
        pageInfo {
          hasNextPage
        }
      }
    }
  `;

  let customers = [];
  let cursor = null;

  do {
    const response = await admin.graphql(query, {
      variables: { cursor },
    });

    const { edges, pageInfo } = response.data.customers;

    // Filter unverified customers
    const unverified = edges
      .filter((e) => !e.node.metafield)
      .map((e) => ({
        id: e.node.id,
        email: e.node.email,
      }));

    customers.push(...unverified);
    cursor = edges[edges.length - 1]?.cursor;
  } while (response.data.customers.pageInfo.hasNextPage);

  return customers;
}

Bulk Verify and Update

async function bulkVerifyCustomers(customers) {
  const emails = customers.map((c) => c.email);

  // Submit bulk verification job
  const job = await emailVerify.verifyBulk(emails);

  // Wait for completion
  const results = await waitForJobCompletion(job.job_id);

  // Update customers with results
  for (const result of results) {
    const customer = customers.find((c) => c.email === result.email);
    if (customer) {
      await updateCustomerVerificationStatus(customer.id, result);
    }
  }

  return results;
}

Best Practices

1. Verify at Multiple Points

  • Registration: Block fake accounts
  • Checkout: Ensure order notifications reach customers
  • Cart abandonment: Don't waste emails on invalid addresses

2. Cache Results

Cache verification results to avoid redundant API calls:

const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours

async function verifyWithCache(email) {
  const cacheKey = `email_verify:${email}`;
  const cached = await redis.get(cacheKey);

  if (cached) {
    return JSON.parse(cached);
  }

  const result = await emailVerify.verify(email);
  await redis.setex(cacheKey, CACHE_DURATION / 1000, JSON.stringify(result));

  return result;
}

3. Handle Edge Cases

function handleVerificationResult(result, context) {
  switch (result.status) {
    case 'valid':
      // Normal flow
      break;

    case 'invalid':
      if (context === 'checkout') {
        // Don't block checkout, just log
        logInvalidEmail(result.email, 'checkout');
      } else if (context === 'registration') {
        // Block registration
        throw new Error('Invalid email');
      }
      break;

    case 'unknown':
      // Accept but flag for review
      flagForReview(result.email);
      break;

    case 'accept_all':
      // Valid but monitor for bounces
      markAsCatchAll(result.email);
      break;
  }
}

4. Monitor and Optimize

Track these metrics:

  • Verification success rate
  • Bounce rate reduction
  • Fake account prevention rate
  • Cart abandonment email deliverability

Verwandte Ressourcen

On this page