Setting up abandoned cart email notifications in 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Configuring Abandoned Cart Email Notifications in 1C-Bitrix

The abandoned cart email is one of the few automated messages with a 5–15% conversion rate. A message sent 1–2 hours after the user leaves the site reaches them while they still remember the product. In 1C-Bitrix, this is implemented using an agent, the main.mail module, and mail event templates.

Core Logic: When to Send

Optimal timing intervals:

  • First email — after 1–2 hours. "You left items in your cart." No discount.
  • Second email — after 24 hours (if no order placed). Reinforce the product's value.
  • Third email — after 72 hours (optional). With a discount or reservation expiry notice.

Do not send all three emails in succession — this creates a negative experience. Stop after the first if the user opened the email, or after the second if they clicked a link.

Mail Event Template

Create a mail event type in Bitrix: Settings → Mail Events → Event Types → Add.

  • Event code: ABANDONED_CART_REMINDER
  • Fields: USER_NAME, USER_EMAIL, CART_ITEMS (HTML table with products), CART_TOTAL, CART_RESTORE_URL, SITE_URL

Email template (Mail Events → Templates → Add):

Subject: #USER_NAME#, you left items in your cart

Hello, #USER_NAME#!

You didn't complete your order. Your cart contains:

#CART_ITEMS#

Total: #CART_TOTAL#

<a href="#CART_RESTORE_URL#">Return to cart</a>

Building the Email Data

class AbandonedCartMailer
{
    public function send(int $userId, int $fuserId): bool
    {
        $user = \Bitrix\Main\UserTable::getById($userId)->fetch();
        if (!$user || !$user['EMAIL']) return false;

        // Check if an order has already been placed
        if ($this->hasRecentOrder($userId)) return false;

        // Get cart items
        $basket = \Bitrix\Sale\Basket::loadItemsForFUser($fuserId, SITE_ID);
        if ($basket->isEmpty()) return false;

        $cartItems = $this->buildCartItemsHtml($basket);
        $cartTotal = number_format($basket->getPrice(), 0, '.', ' ');

        // Cart restoration URL (simply the cart URL — items are already there)
        $cartUrl = SITE_SERVER_NAME . '/basket/';

        \CEvent::Send('ABANDONED_CART_REMINDER', SITE_ID, [
            'USER_NAME'        => $user['NAME'],
            'USER_EMAIL'       => $user['EMAIL'],
            'CART_ITEMS'       => $cartItems,
            'CART_TOTAL'       => $cartTotal,
            'CART_RESTORE_URL' => $cartUrl,
            'SITE_URL'         => SITE_SERVER_NAME,
        ]);

        return true;
    }

    private function buildCartItemsHtml(\Bitrix\Sale\Basket $basket): string
    {
        $html = '<table width="100%" style="border-collapse:collapse">';
        foreach ($basket as $item) {
            $name  = htmlspecialchars($item->getField('NAME'));
            $qty   = (int)$item->getField('QUANTITY');
            $price = number_format($item->getPrice() * $qty, 0, '.', ' ');
            $img   = $this->getProductImage($item->getProductId());

            $html .= "<tr>
                <td width='80'><img src='{$img}' width='70' height='70'></td>
                <td>{$name}<br>Qty: {$qty}</td>
                <td align='right'>{$price}</td>
            </tr>";
        }
        $html .= '</table>';
        return $html;
    }

    private function hasRecentOrder(int $userId): bool
    {
        $cutoff = new \Bitrix\Main\Type\DateTime();
        $cutoff->add('-24 hours');

        $order = \Bitrix\Sale\Order::getList([
            'filter' => ['USER_ID' => $userId, '>DATE_INSERT' => $cutoff],
            'select' => ['ID'],
            'limit'  => 1,
        ])->fetch();

        return (bool)$order;
    }
}

Agent to Trigger the Mailing

// Agent runs every 30 minutes
function sendAbandonedCartEmails(): string
{
    $mailer = new AbandonedCartMailer();

    // Select carts detected 1–2 hours ago with no first email sent yet
    $candidates = AbandonedCartTable::getList([
        'filter' => [
            'STATUS'         => 'new',
            '<DETECTED_AT'   => new \Bitrix\Main\Type\DateTime('-1 hour'),
            '>DETECTED_AT'   => new \Bitrix\Main\Type\DateTime('-2 hours'),
        ],
        'limit' => 50,
    ])->fetchAll();

    foreach ($candidates as $row) {
        $sent = $mailer->send($row['USER_ID'], $row['FUSER_ID']);

        AbandonedCartTable::update($row['ID'], [
            'STATUS'       => $sent ? 'email_sent' : 'skipped',
            'EMAIL_SENT_AT' => $sent ? new \Bitrix\Main\Type\DateTime() : null,
        ]);
    }

    return __FUNCTION__ . '();';
}

Unsubscribe and Consent Management

Under the requirements of Federal Law No. 38 "On Advertising" and GDPR, users must have the ability to opt out. Add an unsubscribe link to the email template:

<a href="#UNSUBSCRIBE_URL#">Unsubscribe from cart reminders</a>

On the Bitrix side — a handler at /local/api/cart-unsubscribe.php that sets the user field UF_NO_CART_EMAIL = Y. Check this field before sending.

Tracking Results

Add UTM parameters to the cart link in the email:

$cartUrl = SITE_SERVER_NAME . '/basket/?utm_source=email&utm_medium=abandoned_cart&utm_campaign=reminder_1h';

GA4 and Metrica will show how many users clicked through from the email and how many of them completed an order.

Timelines: email template creation, agent, sending logic — 3–5 days. With a multi-step email sequence, consent management, and reporting — 1–2 weeks.