Lob Help Center

Mass deletion best practices

Overview

Mass deletion capabilities within Lob allow you to programmatically cancel mail at scale. It is important to have a structure in place to delete mail en masse in the event that users wrongly trigger campaigns to be sent off. Mass deletion involves deleting a large amount of mail items automatically using a specific commonality (for the purpose of this guide, a batch_id, that groups mail pieces by campaign).

Prerequisites

Delete

Need help with mail pieces already created?

If you need assistance with mail deletion, please contact Lob support

Requests should note the following:
- If the cancelation window has already elapsed, canceling is not possible.
- If not elapsed, you will need to provide a list of the resource IDs you would like to have canceled.
- Submitting deletion requests via Support is not a suitable replacement for making deletion requests on your own.

What is mass deletion?

Mass deletion allows the user to cancel large amounts of mail at a single time without canceling all of their outgoing mail. In order to execute a mass deletion, you need a way to identify each individual mail piece that belongs to a campaign. This article shows how to leverage Lob’s metadata property for mass deletion or how to manage mail campaign information with your own infrastructure. Both approaches individually or combined make it easy to cancel all of the mail in reference to a campaign that was released too early or had a mistake in the copy.

Why is mass deletion important?

Oftentimes, users are working on multiple campaigns at one time. One campaign will be set to go out in the near future, and others are staggered for further dates. Sometimes, campaigns that should be going out in the future are accidentally scheduled to be released in the present. When this occurs, it is vital to react fast, so that undesired mail is not sent out because once a mail piece is sent, there is no way to take it out of the mail stream. A campaign may contain thousands of pieces of individual mail and there is no way to manually remove them all in time.  Additionally, you do not want to have to stop ALL of your outgoing mail streams at once due to one mistake. Implementing a mass delete functionality allows users to cancel all of the data in that campaign quickly before it goes to the printer, thereby preventing the user from being charged, and stopping the mail from going out to their customers too early.

Use Lob metadata

The recommended approach for identifying batches of mail sent through Lob is to use the metadata property with a unique key-value pair. Below is an example of how to create a single mail piece that includes metadata with a batch_id set to “NEWYORK2022”. The batch_id can be anything you want as long as it is unique to the batch, is a maximum length of 500 characters and is used for all mail pieces in the batch.

Create a config using your LOB_API_KEY found in the Lob dashboard. Find more on idempotency keys here.

TypeScript

const config: Configuration = new Configuration({
username: "test_XXXXXXXXX",
});
 
const postCardExample: PostcardEditable = {
    to: {
      company: "HARRY ZHANG",
      address_line1: "210 KING STREET",
      address_city: "SAN FRANCISCO",
      address_state: "CA",
      address_zip: "94107",
      address_country: CountryExtended.Us,
    },
    from: {
      company: "LEORE AVIDAR",
      address_line1: "185 BERRY ST",
      address_line2: "SUITE 6100",
      address_city: "SAN FRANCISCO",
      address_state: "CA",
      address_zip: "94107",
      address_country: CountryExtended.Us,
    },
    front = "<html style='padding: 1in; font-size: 50;'>Front HTML</html>",
    back = "<html style='padding: 1in; font-size: 20;'>Back HTML</html>",
    metadata: {
      batch_id: "NEWYORK2022"
   }
 };
const postcardsApi = new PostcardsApi(config);
const postcard = await postcardsApi.create(postCardExample); 
Delete

Python

import lob
lob.api_key = "test_XXXXXXXXX"
 
postcard = lob.Postcard.create(
   to_address = {
     "name": "HARRY ZHANG",
     "address_line1": "210 KING STREET",
     "address_city": "SAN FRANCISCO",
     "address_state": "CA",
     "address_zip": "94107"
   },
   from_address = {
     "name": "LEORE AVIDAR",
     "address_line1":  "185 BERRY STREET",
     "address_line2": "SUITE 6100",
     "address_city": "SAN FRANCISCO",
     "address_state": "CA",
     "address_zip": "94107",
     "address_country": "US"
     },
   front = "<html style='padding: 1in; font-size: 50;'>Front HTML</html>",
   back = "<html style='padding: 1in; font-size: 20;'>Back HTML</html>",
   metadata = {
        "batch_id": "NEWYORK2022"
   }
)
Delete

Ruby 

require 'lob.rb'
require 'pp'
 
lob = Lob::Client.new(api_key: "test_XXXXXX")
 
newPostcard = lob.postcards.create(
   to: {
     name: "HARRY ZHANG",
     address_line1: "210 KING STREET",
     address_city: "SAN FRANCISCO",
     address_state: "CA",
     address_zip: "94107"
   },
   from: {
     name: "LEORE AVIDAR",
     address_line1: "185 BERRY STREET",
     address_line2:  "SUITE 6100",
     address_city: "SAN FRANCISCO",
     address_state: "CA",
     address_zip: "94107"
   },
   front: "<html style='padding: 1in; font-size: 50;'>Front HTML</html>",
   back: "<html style='padding: 1in; font-size: 20;'>Back HTML</html>",
   metadata: {
     "batch_id": "NEWYORK2022"
   }
 )
Delete

PHP

$lob = new \Lob\Lob('test_XXXXXX');
 
$postcard = $lob->postcards()->create(array(
    "to[name]" => "HARRY ZHANG",
    "to[address_line1]" => "210 KING STREET",
    "to[address_city]" => "SAN FRANCISCO",
    "to[address_state]" => "CA",
    "to[address_zip]" => "94107",
    "from[name]"            => "LEORE AVIDAR",
    "from[address_line1]" => "185 BERRY STREET",
    "from[address_line2]" => "SUITE 6100",
    "from[address_city]" => "SAN FRANCISCO",
    "from[address_state]" => "CA",
    "from[address_zip]" => "94107",
    "front" => "<html style='padding: 1in; font-size: 50;'>Front HTML</html>",
    "back" => "<html style='padding: 1in; font-size: 20;'>Back HTML</html>",
     "metadata[batch_id]" => "NEWYORK2022"
));
Delete

Java

import java.util.Map;
import com.lob.Lob;
import com.lob.model.Address;
import com.lob.model.Postcard;
import com.lob.net.LobResponse;
 
public class App 
{
  public static void main( String[] args )
  {
     Lob.init("test_XXXXXXXX");
 
     Map<String, String> metaData = Map.of(
       "batch_id", "NEWYORK2022"
     );
 
     try {
        LobResponse<Postcard> response = new Postcard.RequestBuilder()
         .setTo(
             new Address.RequestBuilder()
                 .setName("HARRY ZHANG")
                 .setLine1("210 KING STREET")
                 .setCity("SAN FRANCISCO")
                 .setState("CA")
                 .setZip("94107")
             )
         .setFrom(
             new Address.RequestBuilder()
                 .setName("LEORE AVIDAR")
                 .setLine1("210 KING STREET")
                 .setCity("SAN FRANCISCO")
                 .setState("CA")
                 .setZip("94107")
             )
         .setFront("<html style='padding: 1in; font-size: 50;'>Front HTML</html>")
         .setBack("<html style='padding: 1in; font-size: 20;'>Back HTML</html>")
         .setMetadata(metaData)
         .create();
 
         Postcard postcard = response.getResponseBody();
         System.out.println(postcard);
      } catch (Exception err) {
         System.out.println("Error on postcard creation: " + err);
      }
    }
 }
Delete

In order to delete all postcards from the NEWYORK2022 campaign, use the list function and pass a metadata object with a batch_id key set to NEWYORK2022. This returns a list of all NEWYORK2022 campaign postcards, loop over each one and pass the postcard id into the cancel function.

To see the full list of acceptable parameters in the list, visit the docs.

TypeScript

const config: Configuration = new Configuration({
username: "test_XXXXXXXXX",
});
const postcardsApi = new PostcardsApi(config);
const listOfPostcards = await postcardsApi.list(
    undefined,
    undefined,
    undefined,
    undefined,
    undefined,
    { batch_id: "NEWYORK2022" }
);
 
 for (let postcard of listOfPostcards) {
     await postcardsApi.cancel(postcard.id);
}
Delete

Python

import lob
lob.api_key = "test_XXXXXXXXXXXXXX"
 
 list_of_postcards = lob.Postcard.list(metadata={"batch_id": "NEWYORK2022"})
 
for i in list_of_postcards.data: 
   lob.Postcard.delete(i.id)
Delete

Ruby

require 'lob.rb'
require 'pp'
require 'json'
 
lob = Lob::Client.new(api_key: "test_XXXXXXXXXX")
 
list = lob.postcards.list(metadata: {"batch_id": "NEWYORK2022"})
data = list['data']
 
data.each do |item|
   begin
      lob.postcards.destroy( item['id'])
   rescue Lob::InvalidRequestError => e
      obj = JSON.parse(e.json_body)
      pp obj['error']['message']
   end
 end
Delete

PHP

$metadata = ["batch_id" => "NEWYORK2022"];
$list = $lob->postcards()->all(array('metadata' => $metadata));
 
foreach($list['data'] as $item) {
    try {
        $lob->postcards()->delete($item['id']);
    } catch (Exception $e) {
        echo 'Caught exception: ', $e->getMessage(), "\n";
    }
}
Delete

Java

import java.util.Map;
import java.util.HashMap;
import com.lob.Lob;
import com.lob.model.PostcardCollection;
import com.lob.model.Postcard;
import com.lob.net.LobResponse;
 
public class App 
{
   public static void main( String[] args )
   {
     Lob.init("test_XXXXXXXXX");
 
     Map<String, String> metaData = Map.of(
         "batch_id", "NEWYORK2022"
     );
 
     Map<String, Object> params = new HashMap<>();
     params.put("metadata", metaData);
 
     try {
         LobResponse<PostcardCollection> listResp = Postcard.list(params);
         PostcardCollection list = listResp.getResponseBody();
 
         for(int i=0; i<list.getCount(); i++) {
           try {
               LobResponse<Postcard> deleteResponse = Postcard.delete(list.getData().get(i).getId());
           } catch (Exception err) {
               System.out.println("Error: " + err);
           }
         }            
     } catch (Exception err) {
         System.out.println("Error: " + err);
     }
   }
 }
Delete

Utilize your own infrastructure

If you plan to save details about individual mail pieces in your database, consider including an identifier for the campaign as well. In the example below, we create a new postcard and upon successful completion, we store details in our database.

Create a config using your LOB_API_KEY found in the lob dashboard. Note: For extra resiliency, you can pass in the batch id via metadata (see above example), as well as store it locally as seen below.

TypeScript

const config: Configuration = new Configuration({
username: "test_XXXXXXXXX",
});
const postCardExample: PostcardEditable = {
    to: {
      name: "HARRY ZHANG",
      address_line1: "210 KING STREET",
      address_city: "SAN FRANCISCO",
      address_state: "CA",
      address_zip: "94107",
      address_country: CountryExtended.Us,
    },
    from: {
      name: "LEORE AVIDAR",
      address_line1: "185 BERRY ST",
      address_line2: "SUITE 6100",
      address_city: "SAN FRANCISCO",
      address_state: "CA",
      address_zip: "94107",
      address_country: CountryExtended.Us,
    }
};
const postcardsApi = new PostcardsApi(config);
const postcard = await postcardsApi.create(postCardExample);
  
/* Save to your database with the postcard.id and a unique group id */ 
Delete

Python

import lob
lob.api_key = "test_XXXXXXXXX"
 
postcard = lob.Postcard.create(
   to_address = {
     "name": "HARRY ZHANG",
     "address_line1": "210 KING STREET",
     "address_city": "SAN FRANCISCO",
     "address_state": "CA",
     "address_zip": "94107"
   },
   from_address = {
     "name": "LEORE AVIDAR",
     "address_line1":  "185 BERRY ST",
     "address_line2": "SUITE 6100",
     "address_city": "SAN FRANCISCO",
     "address_state": "CA",
     "address_zip": "94107",
     "address_country": "US"
     },
   front = "<html style='padding: 1in; font-size: 50;'>Front HTML for Postcard</html>",
   back = "<html style='padding: 1in; font-size: 20;'>Back HTML for Postcard</html>"
)
  
# Save to your database with the postcard.id and a unique group id 
Delete

Ruby

require 'lob.rb'
require 'pp'
 
lob = Lob::Client.new(api_key: "test_XXXXXX")
 
newPostcard = lob.postcards.create(
   to: {
     name: "HARRY ZHANG",
     address_line1: "210 KING STREET",
     address_city: "SAN FRANCISCO",
     address_state: "CA",
     address_zip: "94107"
   },
   from: {
     name: "LEORE AVIDAR",
     address_line1: "185 BERRY ST",
     address_line2:  "SUITE 6100",
     address_city: "SAN FRANCISCO",
     address_state: "CA",
     address_zip: "94107"
   },
   front: "<html style='padding: 1in; font-size: 50;'>Front HTML</html>",
   back: "<html style='padding: 1in; font-size: 20;'>Back HTML</html>"
 )
//Save to your database with the postcard.id and a unique group id  
Delete

PHP

$lob = new \Lob\Lob('test_XXXXXX');
 
 $postcard = $lob->postcards()->create(array(
    "to[name]" => "HARRY ZHANG",
    "to[address_line1]" => "210 KING STREET",
    "to[address_city]" => "SAN FRANCISCO",
    "to[address_state]" => "CA",
    "to[address_zip]" => "94107",
    "from[name]"            => "LEORE AVIDAR",
    "from[address_line1]" => "185 BERRY STREET",
    "from[address_line2]" => "SUITE 6100",
    "from[address_city]" => "SAN FRANCISCO",
    "from[address_state]" => "CA",
    "from[address_zip]" => "94107",
    "front" => "<html style='padding: 1in; font-size: 50;'>Front HTML</html>",
    "back" => "<html style='padding: 1in; font-size: 20;'>Back HTML</html>"
));
 /* Save to your database with the postcard.id and a unique group id */   
Delete

Java

import java.util.Map;
import com.lob.Lob;
import com.lob.model.Address;
import com.lob.model.Postcard;
import com.lob.net.LobResponse;
 
public class App 
{
  public static void main( String[] args )
  {
     Lob.init("test_XXXXXXXX");
 
     try {
        LobResponse<Postcard> response = new Postcard.RequestBuilder()
         .setTo(
             new Address.RequestBuilder()
                 .setName("HARRY ZHANG")
                 .setLine1("210 KING STREET")
                 .setCity("SAN FRANCISCO")
                 .setState("CA")
                 .setZip("94107")
             )
         .setFrom(
             new Address.RequestBuilder()
                 .setName("LEORE AVIDAR")
                 .setLine1("210 KING STREET")
                 .setCity("SAN FRANCISCO")
                 .setState("CA")
                 .setZip("94107")
             )
         .setFront("<html style='padding: 1in; font-size: 50;'>Front HTML</html>")
         .setBack("<html style='padding: 1in; font-size: 20;'>Back HTML</html>")
         .create();
         /* Save to your database with the postcard.id and a unique group id */  
 
      } catch (Exception err) {
         System.out.println("Error on postcard creation: " + err);
      }
    }
 }
 
Delete

To mass delete, we fetch a list of mail pieces from our database using a unique id for our campaign and loop over all the mail pieces to cancel them.

TypeScript

Fetch the list ids from your database using your unique group id

const config: Configuration = new Configuration({
    username: LOB_API_KEY,
});
const postcardsApi = new PostcardsApi(config); 
 
for (let item of dbdata) {
 await postcardsApi.cancel(item.id);
 
     /* Remove the record from your database */ 
 }
Delete

Python

Fetch the list ids from your database using your unique group id

import lob
lob.api_key = "test_XXXXXXXXXX"
 
for i in dbdata: 
 lob.Postcard.delete(i.id)
    /* Remove the record from your database */ 
Delete

Ruby

Fetch the list ids from your database using your unique group id
 
dbdata.each do | item |
   begin
     lob.postcards.destroy( item['id'])
      # Remove the record from your database  
   rescue Lob::InvalidRequestError => e
     obj = JSON.parse(e.json_body)
     pp obj['error']['message']
   end
 end
Delete


PHP

Fetch the list ids from your database using your unique group id
 
foreach($dbdata as $item) {
    try {
        $lob->postcards()->delete($item['id']);
        /* Remove the record from your database */ 
    } catch (Exception $e) {
        echo 'Caught exception: ', $e->getMessage(), "\n";
    }
}
Delete

Java

Fetch the list ids from your database using your unique group id
 
import java.util.Map;
import java.util.HashMap;
import com.lob.Lob;
import com.lob.model.PostcardCollection;
import com.lob.model.Postcard;
import com.lob.net.LobResponse;
 
public class App 
{
   public static void main( String[] args )
   {
     Lob.init("test_XXXXXXXXX");
 
     for(int i=0; i<list.getCount(); i++) {
       try {
           LobResponse<Postcard> deleteResponse = Postcard.delete(list.getData().get(i).getId());
            /* delete record from your database */ 
 
        } catch (Exception err) {
           System.out.println("Error: " + err);
       }
     } 
   }
 }
Delete

Conclusion

In this article, you have learned how to add metadata to mail pieces. Using this metadata you can fetch a list of related mail pieces and delete them en masse. With these code snippets, you can ensure that accidentally triggering a mail campaign early does not cost you money, time, or customers.

Further resources

Was this article helpful?