diff --git a/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/AddCustomerMatchUserList.java b/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/AddCustomerMatchUserList.java
index f9a8b5f07c..97f725097a 100644
--- a/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/AddCustomerMatchUserList.java
+++ b/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/AddCustomerMatchUserList.java
@@ -81,8 +81,8 @@
* https://support.google.com/adspolicy/answer/6299717.
*
It may take up to several hours for the list to be populated with members.
* Email addresses must be associated with a Google account.
- * For privacy purposes, the user list size will show as zero until the list has at least
- * 100 members. After that, the size will be rounded to the two most significant digits.
+ * For privacy purposes, the user list size will show as zero until the list has at least 100
+ * members. After that, the size will be rounded to the two most significant digits.
*
*/
public class AddCustomerMatchUserList {
@@ -423,14 +423,14 @@ private List buildOfflineUserDataJobOperations()
ImmutableMap.builder()
.put("email", "dana@example.com")
// Phone number to be converted to E.164 format, with a leading '+' as required. This
- // includes whitespace that will be removed later.
- .put("phone", "+1 800 5550101")
+ // includes whitespace, dashes, and parentheses that will be removed later.
+ .put("phone", "+1 (800) 555-0101")
.build();
// The second user data has an email address, a mailing address, and a phone number.
Map rawRecord2 =
ImmutableMap.builder()
- // Email address that includes a period (.) before the domain.
- .put("email", "alex.2@example.com")
+ // Email address that includes a period (.) and plus (+) suffix before the Gmail domain.
+ .put("email", "alex.2+myalias@gmail.com")
// Address that includes all four required elements: first name, last name, country
// code, and postal code.
.put("firstName", "Alex")
@@ -438,7 +438,7 @@ private List buildOfflineUserDataJobOperations()
.put("countryCode", "US")
.put("postalCode", "94045")
// Phone number to be converted to E.164 format, with a leading '+' as required.
- .put("phone", "+1 800 5550102")
+ .put("phone", "+1 800-555-0102")
.build();
// The third user data only has an email address.
Map rawRecord3 =
@@ -479,7 +479,7 @@ private List buildOfflineUserDataJobOperations()
if (rawRecord.containsKey("email")) {
UserIdentifier hashedEmailIdentifier =
UserIdentifier.newBuilder()
- .setHashedEmail(normalizeAndHash(sha256Digest, rawRecord.get("email"), true))
+ .setHashedEmail(normalizeAndHashEmailAddress(sha256Digest, rawRecord.get("email")))
.build();
// Adds the hashed email identifier to the UserData object's list.
userDataBuilder.addUserIdentifiers(hashedEmailIdentifier);
@@ -489,7 +489,8 @@ private List buildOfflineUserDataJobOperations()
if (rawRecord.containsKey("phone")) {
UserIdentifier hashedPhoneNumberIdentifier =
UserIdentifier.newBuilder()
- .setHashedPhoneNumber(normalizeAndHash(sha256Digest, rawRecord.get("phone"), true))
+ .setHashedPhoneNumber(
+ normalizeAndHashPhoneNumber(sha256Digest, rawRecord.get("phone")))
.build();
// Adds the hashed phone number identifier to the UserData object's list.
userDataBuilder.addUserIdentifiers(hashedPhoneNumberIdentifier);
@@ -578,6 +579,50 @@ private String normalizeAndHash(MessageDigest digest, String s, boolean trimInte
return result.toString();
}
+ /**
+ * Returns the result of normalizing and hashing an email address. For this use case, Google Ads
+ * requires removal of any '.' characters or trailing '+' and characters that follow it from the
+ * username portion of the email address if the domain is {@code gmail.com} or {@code
+ * googlemail.com}.
+ *
+ * @param digest the digest to use to hash the normalized string.
+ * @param emailAddress the email address to normalize and hash.
+ */
+ private String normalizeAndHashEmailAddress(MessageDigest digest, String emailAddress)
+ throws UnsupportedEncodingException {
+ // Removes all whitespace (leading, trailing, and intermediate) from the email address.
+ String normalizedEmail = emailAddress.toLowerCase().replaceAll("\\s+", "");
+ String[] emailParts = normalizedEmail.split("@", 2);
+ if (emailParts.length == 2 && emailParts[1].matches("^(gmail|googlemail)\\.com$")) {
+ // Removes any '.' characters from the portion of the email address before the domain if the
+ // domain is gmail.com or googlemail.com.
+ emailParts[0] = emailParts[0].replaceAll("\\.", "");
+ // Removes any '+' and all characters that follow it from the portion of the email address
+ // before the domain if the domain is gmail.com or googlemail.com.
+ emailParts[0] = emailParts[0].replaceAll("\\+.*", "");
+ normalizedEmail = String.format("%s@%s", emailParts[0], emailParts[1]);
+ }
+ return normalizeAndHash(digest, normalizedEmail, true);
+ }
+
+ /**
+ * Returns the result of normalizing and hashing a phone number. For this use case, Google Ads
+ * requires phone numbers to be in E.164 format.
+ *
+ * @param digest the digest to use to hash the normalized string.
+ * @param phoneNumber the phone number to normalize and hash.
+ */
+ private String normalizeAndHashPhoneNumber(MessageDigest digest, String phoneNumber)
+ throws UnsupportedEncodingException {
+ // Removes non-digit characters and prepends a leading '+' sign.
+ String digitsOnly = phoneNumber.replaceAll("[^0-9]", "");
+ String formattedPhone = "+" + digitsOnly;
+ if (!formattedPhone.matches("^\\+[1-9]\\d{6,14}$")) {
+ throw new IllegalArgumentException("Phone number must be in E.164 format: " + phoneNumber);
+ }
+ return normalizeAndHash(digest, formattedPhone, true);
+ }
+
/**
* Retrieves, checks, and prints the status of the offline user data job.
*
diff --git a/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadEnhancedConversionsForLeads.java b/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadEnhancedConversionsForLeads.java
index aaa87a4f0b..34f9d3c964 100644
--- a/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadEnhancedConversionsForLeads.java
+++ b/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadEnhancedConversionsForLeads.java
@@ -86,18 +86,17 @@ private static class UploadEnhancedConversionsForLeadsParams extends CodeSampleP
names = ArgumentNames.SESSION_ATTRIBUTES_ENCODED,
required = false,
description =
- "A session attributes token. Only one of sessionAttributesEncoded or sessionAttributesMap"
- + " should be passed.")
+ "A session attributes token. Only one of sessionAttributesEncoded or"
+ + " sessionAttributesMap should be passed.")
private String sessionAttributesEncoded;
@Parameter(
names = ArgumentNames.SESSION_ATTRIBUTES_MAP,
required = false,
description =
- "A "
- + "space-delimited list of session attribute key value pairs. Each pair should be "
- + "separated by an equal sign, for example: 'gad_campaignid=12345 gad_source=1'. Only "
- + "one of sessionAttributesEncoded or sessionAttributesMap should be passed.")
+ "A space-delimited list of session attribute key value pairs. Each pair should be"
+ + " separated by an equal sign, for example: 'gad_campaignid=12345 gad_source=1'."
+ + " Only one of sessionAttributesEncoded or sessionAttributesMap should be passed.")
private String sessionAttributesMap;
}
@@ -217,9 +216,9 @@ private void runExample(
ImmutableMap.Builder rawRecordBuilder =
ImmutableMap.builder()
- .put("email", "alex.2@example.com")
+ .put("email", "alex.2+myalias@gmail.com")
// Phone number to be converted to E.164 format, with a leading '+' as required.
- .put("phone", "+1 800 5550102")
+ .put("phone", "+1 (800) 555-0102")
// This example lets you put conversion details as arguments, but in reality you might
// store this data alongside other user data, so we include it in this sample user
// record.
@@ -269,7 +268,7 @@ private void runExample(
// Creates a user identifier using normalized and hashed phone info.
UserIdentifier hashedPhoneNumberIdentifier =
UserIdentifier.newBuilder()
- .setHashedPhoneNumber(normalizeAndHash(sha256Digest, rawRecord.get("phone")))
+ .setHashedPhoneNumber(normalizeAndHashPhoneNumber(sha256Digest, rawRecord.get("phone")))
.build();
// Adds the hashed phone number identifier to the UserData object's list.
userIdentifiers.add(hashedPhoneNumberIdentifier);
@@ -324,9 +323,10 @@ private void runExample(
String[] parts = pair.split("=", 2);
if (parts.length != 2) {
throw new IllegalArgumentException(
- "Failed to read the sessionAttributesMap. SessionAttributesMap must use a "
- + "space-delimited list of session attribute key value pairs. Each pair should be"
- + " separated by an equal sign, for example: 'gad_campaignid=12345 gad_source=1'");
+ "Failed to read the sessionAttributesMap. SessionAttributesMap must use a"
+ + " space-delimited list of session attribute key value pairs. Each pair should"
+ + " be separated by an equal sign, for example: 'gad_campaignid=12345"
+ + " gad_source=1'");
}
sessionAttributePairs.addKeyValuePairs(
SessionAttributeKeyValuePair.newBuilder()
@@ -409,22 +409,46 @@ private String normalizeAndHash(MessageDigest digest, String s)
/**
* Returns the result of normalizing and hashing an email address. For this use case, Google Ads
- * requires removal of any '.' characters preceding {@code gmail.com} or {@code googlemail.com}.
+ * requires removal of any '.' characters or trailing '+' and characters that follow it from the
+ * username portion of the email address if the domain is {@code gmail.com} or {@code
+ * googlemail.com}.
*
* @param digest the digest to use to hash the normalized string.
* @param emailAddress the email address to normalize and hash.
*/
private String normalizeAndHashEmailAddress(MessageDigest digest, String emailAddress)
throws UnsupportedEncodingException {
- String normalizedEmail = emailAddress.toLowerCase();
- String[] emailParts = normalizedEmail.split("@");
- if (emailParts.length > 1 && emailParts[1].matches("^(gmail|googlemail)\\.com\\s*")) {
+ // Removes all whitespace (leading, trailing, and intermediate) from the email address.
+ String normalizedEmail = emailAddress.toLowerCase().replaceAll("\\s+", "");
+ String[] emailParts = normalizedEmail.split("@", 2);
+ if (emailParts.length == 2 && emailParts[1].matches("^(gmail|googlemail)\\.com$")) {
// Removes any '.' characters from the portion of the email address before the domain if the
// domain is gmail.com or googlemail.com.
emailParts[0] = emailParts[0].replaceAll("\\.", "");
+ // Removes any '+' and all characters that follow it from the portion of the email address
+ // before the domain if the domain is gmail.com or googlemail.com.
+ emailParts[0] = emailParts[0].replaceAll("\\+.*", "");
normalizedEmail = String.format("%s@%s", emailParts[0], emailParts[1]);
}
return normalizeAndHash(digest, normalizedEmail);
}
+
+ /**
+ * Returns the result of normalizing and hashing a phone number. For this use case, Google Ads
+ * requires phone numbers to be in E.164 format.
+ *
+ * @param digest the digest to use to hash the normalized string.
+ * @param phoneNumber the phone number to normalize and hash.
+ */
+ private String normalizeAndHashPhoneNumber(MessageDigest digest, String phoneNumber)
+ throws UnsupportedEncodingException {
+ // Removes non-digit characters and prepends a leading '+' sign.
+ String digitsOnly = phoneNumber.replaceAll("[^0-9]", "");
+ String formattedPhone = "+" + digitsOnly;
+ if (!formattedPhone.matches("^\\+[1-9]\\d{6,14}$")) {
+ throw new IllegalArgumentException("Phone number must be in E.164 format: " + phoneNumber);
+ }
+ return normalizeAndHash(digest, formattedPhone);
+ }
// [END normalize_and_hash]
}
diff --git a/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadEnhancedConversionsForWeb.java b/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadEnhancedConversionsForWeb.java
index 329f8e872c..9aa0a325c9 100644
--- a/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadEnhancedConversionsForWeb.java
+++ b/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadEnhancedConversionsForWeb.java
@@ -171,9 +171,8 @@ private void runExample(
ImmutableMap.Builder rawRecordBuilder =
ImmutableMap.builder()
- .put("email", "alex.2@example.com")
- // Email address that includes a period (.) before the Gmail domain.
- .put("email", "alex.2@example.com")
+ // Email address that includes a period (.) and plus (+) suffix before the Gmail domain.
+ .put("email", "alex.2+myalias@gmail.com")
// Address that includes all four required elements: first name, last name, country
// code, and postal code.
.put("firstName", "Alex")
@@ -181,7 +180,7 @@ private void runExample(
.put("countryCode", "US")
.put("postalCode", "94045")
// Phone number to be converted to E.164 format, with a leading '+' as required.
- .put("phone", "+1 800 5550102")
+ .put("phone", "+1 800-555-0102")
// This example lets you put conversion details as arguments, but in reality you might
// store this data alongside other user data, so we include it in this sample user
// record.
@@ -222,7 +221,8 @@ private void runExample(
if (rawRecord.containsKey("phone")) {
UserIdentifier hashedPhoneNumberIdentifier =
UserIdentifier.newBuilder()
- .setHashedPhoneNumber(normalizeAndHash(sha256Digest, rawRecord.get("phone"), true))
+ .setHashedPhoneNumber(
+ normalizeAndHashPhoneNumber(sha256Digest, rawRecord.get("phone")))
.build();
// Adds the hashed phone number identifier to the UserData object's list.
userIdentifiers.add(hashedPhoneNumberIdentifier);
@@ -363,22 +363,46 @@ private String normalizeAndHash(MessageDigest digest, String s, boolean trimInte
/**
* Returns the result of normalizing and hashing an email address. For this use case, Google Ads
- * requires removal of any '.' characters preceding {@code gmail.com} or {@code googlemail.com}.
+ * requires removal of any '.' characters or trailing '+' and characters that follow it from the
+ * username portion of the email address if the domain is {@code gmail.com} or {@code
+ * googlemail.com}.
*
* @param digest the digest to use to hash the normalized string.
* @param emailAddress the email address to normalize and hash.
*/
private String normalizeAndHashEmailAddress(MessageDigest digest, String emailAddress)
throws UnsupportedEncodingException {
- String normalizedEmail = emailAddress.toLowerCase();
- String[] emailParts = normalizedEmail.split("@");
- if (emailParts.length > 1 && emailParts[1].matches("^(gmail|googlemail)\\.com\\s*")) {
+ // Removes all whitespace (leading, trailing, and intermediate) from the email address.
+ String normalizedEmail = emailAddress.toLowerCase().replaceAll("\\s+", "");
+ String[] emailParts = normalizedEmail.split("@", 2);
+ if (emailParts.length == 2 && emailParts[1].matches("^(gmail|googlemail)\\.com$")) {
// Removes any '.' characters from the portion of the email address before the domain if the
// domain is gmail.com or googlemail.com.
emailParts[0] = emailParts[0].replaceAll("\\.", "");
+ // Removes any '+' and all characters that follow it from the portion of the email address
+ // before the domain if the domain is gmail.com or googlemail.com.
+ emailParts[0] = emailParts[0].replaceAll("\\+.*", "");
normalizedEmail = String.format("%s@%s", emailParts[0], emailParts[1]);
}
return normalizeAndHash(digest, normalizedEmail, true);
}
+
+ /**
+ * Returns the result of normalizing and hashing a phone number. For this use case, Google Ads
+ * requires phone numbers to be in E.164 format.
+ *
+ * @param digest the digest to use to hash the normalized string.
+ * @param phoneNumber the phone number to normalize and hash.
+ */
+ private String normalizeAndHashPhoneNumber(MessageDigest digest, String phoneNumber)
+ throws UnsupportedEncodingException {
+ // Removes non-digit characters and prepends a leading '+' sign.
+ String digitsOnly = phoneNumber.replaceAll("[^0-9]", "");
+ String formattedPhone = "+" + digitsOnly;
+ if (!formattedPhone.matches("^\\+[1-9]\\d{6,14}$")) {
+ throw new IllegalArgumentException("Phone number must be in E.164 format: " + phoneNumber);
+ }
+ return normalizeAndHash(digest, formattedPhone, true);
+ }
// [END normalize_and_hash]
}
diff --git a/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadStoreSalesTransactions.java b/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadStoreSalesTransactions.java
index 61d495938f..5e6b0b2a4f 100644
--- a/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadStoreSalesTransactions.java
+++ b/google-ads-examples/src/main/java/com/google/ads/googleads/examples/remarketing/UploadStoreSalesTransactions.java
@@ -562,7 +562,7 @@ private List buildOfflineUserDataJobOperations(
throw new RuntimeException("Missing SHA-256 algorithm implementation", e);
}
- // Create the first transaction for upload based on an email address and state.
+ // Create the first transaction for upload based on an email address, phone number, and state.
UserData.Builder userDataWithEmailAddress =
UserData.newBuilder()
.addAllUserIdentifiers(
@@ -570,7 +570,12 @@ private List buildOfflineUserDataJobOperations(
UserIdentifier.newBuilder()
.setHashedEmail(
// Email addresses must be normalized and hashed.
- normalizeAndHash(sha256Digest, "dana@example.com"))
+ normalizeAndHashEmailAddress(sha256Digest, "dana.2+myalias@gmail.com"))
+ .build(),
+ UserIdentifier.newBuilder()
+ .setHashedPhoneNumber(
+ // Phone numbers must be normalized and hashed.
+ normalizeAndHashPhoneNumber(sha256Digest, "+1 (800) 555-0101"))
.build(),
UserIdentifier.newBuilder()
.setAddressInfo(OfflineUserAddressInfo.newBuilder().setState("NY"))
@@ -675,6 +680,50 @@ private String normalizeAndHash(MessageDigest digest, String s)
return result.toString();
}
+ /**
+ * Returns the result of normalizing and hashing an email address. For this use case, Google Ads
+ * requires removal of any '.' characters or trailing '+' and characters that follow it from the
+ * username portion of the email address if the domain is {@code gmail.com} or {@code
+ * googlemail.com}.
+ *
+ * @param digest the digest to use to hash the normalized string.
+ * @param emailAddress the email address to normalize and hash.
+ */
+ private String normalizeAndHashEmailAddress(MessageDigest digest, String emailAddress)
+ throws UnsupportedEncodingException {
+ // Removes all whitespace (leading, trailing, and intermediate) from the email address.
+ String normalizedEmail = emailAddress.toLowerCase().replaceAll("\\s+", "");
+ String[] emailParts = normalizedEmail.split("@", 2);
+ if (emailParts.length == 2 && emailParts[1].matches("^(gmail|googlemail)\\.com$")) {
+ // Removes any '.' characters from the portion of the email address before the domain if the
+ // domain is gmail.com or googlemail.com.
+ emailParts[0] = emailParts[0].replaceAll("\\.", "");
+ // Removes any '+' and all characters that follow it from the portion of the email address
+ // before the domain if the domain is gmail.com or googlemail.com.
+ emailParts[0] = emailParts[0].replaceAll("\\+.*", "");
+ normalizedEmail = String.format("%s@%s", emailParts[0], emailParts[1]);
+ }
+ return normalizeAndHash(digest, normalizedEmail);
+ }
+
+ /**
+ * Returns the result of normalizing and hashing a phone number. For this use case, Google Ads
+ * requires phone numbers to be in E.164 format.
+ *
+ * @param digest the digest to use to hash the normalized string.
+ * @param phoneNumber the phone number to normalize and hash.
+ */
+ private String normalizeAndHashPhoneNumber(MessageDigest digest, String phoneNumber)
+ throws UnsupportedEncodingException {
+ // Removes non-digit characters and prepends a leading '+' sign.
+ String digitsOnly = phoneNumber.replaceAll("[^0-9]", "");
+ String formattedPhone = "+" + digitsOnly;
+ if (!formattedPhone.matches("^\\+[1-9]\\d{6,14}$")) {
+ throw new IllegalArgumentException("Phone number must be in E.164 format: " + phoneNumber);
+ }
+ return normalizeAndHash(digest, formattedPhone);
+ }
+
/** Retrieves, checks, and prints the status of the offline user data job. */
private void checkJobStatus(
GoogleAdsClient googleAdsClient, long customerId, String offlineUserDataJobResourceName) {