AWS lambda cannot read dynamodb table and send mail using sendgrid - node.js

I want to send the mail using sendgrid in lambda function cannot send mail and read the dynamodb database but when I test in lambda console it shows null but when I test using locally it works
const moment = require("moment")();
const AWS = require("aws-sdk");
const sgMail = require("#sendgrid/mail");
AWS.config.getCredentials((err) => {
if (err) return err;
});
sgMail.setApiKey(
MYKEY
);
AWS.config.update({ region: "us-east-1" });
const dynamodb = new AWS.DynamoDB({ apiVersion: "2012-08-10" });
const ddb = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event) => {
var currentDate = `${moment.date()}/${moment.month() + 1}`;
console.log(`EXECUTION DATE: ${currentDate}`);
// 1) Match with Dynamodb birthday table
var params = {
FilterExpression: "#cg = :data",
ExpressionAttributeNames: {
"#cg": "birthDate",
},
ExpressionAttributeValues: {
":data": currentDate,
},
TableName: "Users",
};
try {
// 2) Result
var result = ddb.scan(params).promise();
result
.then((items) => {
console.log("items");
if (items["Count"] > 0) {
items["Items"].map((user) => {
// Send mail
const msg = {
to: user.mail,
from: {
email: "test#example.com",
name: "Bhautik",
},
reply_to: {
email: "test#example.com",
name: "Bhautik",
},
subject: `Happy Birthday, ${user.name} 😊`,
text: "I hope you have a great day today...",
html:
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html data-editor-version="2" class="sg-campaigns" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"><!--[if (gte mso 9)|(IE)]> <xml> <o:OfficeDocumentSettings> <o:AllowPNG/> <o:PixelsPerInch>96</o:PixelsPerInch> </o:OfficeDocumentSettings> </xml><![endif]--><!--[if (gte mso 9)|(IE)]> <style type="text/css"> body{width: 600px;margin: 0 auto;}table{border-collapse: collapse;}table, td{mso-table-lspace: 0pt;mso-table-rspace: 0pt;}img{-ms-interpolation-mode: bicubic;}</style><![endif]--> <style type="text/css"> body, p, div{font-family: arial,helvetica,sans-serif; font-size: 14px;}body{color: #000000;}body a{color: #1188E6; text-decoration: none;}p{margin: 0; padding: 0;}table.wrapper{width:100% !important; table-layout: fixed; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: 100%; -moz-text-size-adjust: 100%; -ms-text-size-adjust: 100%;}img.max-width{max-width: 100% !important;}.column.of-2{width: 50%;}.column.of-3{width: 33.333%;}.column.of-4{width: 25%;}#media screen and (max-width:480px){.preheader .rightColumnContent, .footer .rightColumnContent{text-align: left !important;}.preheader .rightColumnContent div, .preheader .rightColumnContent span, .footer .rightColumnContent div, .footer .rightColumnContent span{text-align: left !important;}.preheader .rightColumnContent, .preheader .leftColumnContent{font-size: 80% !important; padding: 5px 0;}table.wrapper-mobile{width: 100% !important; table-layout: fixed;}img.max-width{height: auto !important; max-width: 100% !important;}a.bulletproof-button{display: block !important; width: auto !important; font-size: 80%; padding-left: 0 !important; padding-right: 0 !important;}.columns{width: 100% !important;}.column{display: block !important; width: 100% !important; padding-left: 0 !important; padding-right: 0 !important; margin-left: 0 !important; margin-right: 0 !important;}.social-icon-column{display: inline-block !important;}}</style> </head> <body> <center class="wrapper" data-link-color="#1188E6" data-body-style="font-size:14px; font-family:arial,helvetica,sans-serif; color:#000000; background-color:#FFFFFF;"> <div class="webkit"> <table cellpadding="0" cellspacing="0" border="0" width="100%" class="wrapper" bgcolor="#FFFFFF"> <tr> <td valign="top" bgcolor="#FFFFFF" width="100%"> <table width="100%" role="content-container" class="outer" align="center" cellpadding="0" cellspacing="0" border="0"> <tr> <td width="100%"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td><!--[if mso]> <center> <table><tr><td width="600"><![endif]--> <table width="100%" cellpadding="0" cellspacing="0" border="0" style="width:100%; max-width:600px;" align="center"> <tr> <td role="modules-container" style="padding:0px 0px 0px 0px; color:#000000; text-align:left;" bgcolor="#FFFFFF" width="100%" align="left"><table class="module preheader preheader-hide" role="module" data-type="preheader" border="0" cellpadding="0" cellspacing="0" width="100%" style="display: none !important; mso-hide: all; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;"> <tr> <td role="module-content"> <p>I hope you have a great day today...</p></td></tr></table><table class="wrapper" role="module" data-type="image" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="64efa4d4-043b-4982-a412-9d010d10b043"> <tbody> <tr> <td style="font-size:6px; line-height:10px; padding:0px 0px 0px 0px;" valign="top" align="center"> <img class="max-width" border="0" style="display:block; color:#000000; text-decoration:none; font-family:Helvetica, arial, sans-serif; font-size:16px;" width="512" alt="" data-proportionally-constrained="true" data-responsive="false" src="http://cdn.mcauto-images-production.sendgrid.net/82cf15c98221d9d9/1cf0943b-5037-4305-bd81-551fb7d3e346/512x496.png" height="496"> </td></tr></tbody> </table></td></tr></table><!--[if mso]> </td></tr></table> </center><![endif]--> </td></tr></table> </td></tr></table> </td></tr></table> </div></center> </body> </html>',
};
sgMail
.send(msg)
.then((res) => {
console.log("mail sent!!");
})
.catch((err) => {
console.log(err);
return `Error: ${err}`;
});
});
}
})
.catch((err) => {
console.log(err);
return `Error: ${err}`;
});
} catch (e) {
console.log(e);
return `Error: ${e}`;
}
};
Here is my steps in index.js
1) Fetch today date using momentjs
2) Scan the items whose birthDate is equal to today date
3) Send mail using sendgrid mail API.

Solved using fetched items put into Promise.all()
const moment = require("moment")();
const AWS = require("aws-sdk");
const sgMail = require("#sendgrid/mail");
AWS.config.getCredentials((err) => {
if (err) return err;
});
sgMail.setApiKey(
MyKey
);
AWS.config.update({ region: "us-east-1" });
const dynamodb = new AWS.DynamoDB({ apiVersion: "2012-08-10" });
const ddb = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event) => {
var currentDate = `${moment.date()}/${moment.month() + 1}`;
console.log(`EXECUTION DATE: ${currentDate}`);
// 1) Match with Dynamodb birthday table
var params = {
FilterExpression: "#cg = :data",
ExpressionAttributeNames: {
"#cg": "birthDate",
},
ExpressionAttributeValues: {
":data": currentDate,
},
TableName: "Users",
};
try {
// 2) Result
var result = await ddb.scan(params).promise();
if(result.Count > 0) {
console.log(`Today Birthdays: ${result.Count}`);
let final = await Promise.all(
result.Items.map(async (user) => {
console.log(`Sending mail to ${user.mail}`);
const msg = {
to: user.mail,
from: {
email: "someone#example.com",
name: "Bhautik",
},
reply_to: {
email: "someone#example.com",
name: "Bhautik",
},
subject: `Happy Birthday, ${user.name} 😊`,
text: "I hope you have a great day today...",
html:
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html data-editor-version="2" class="sg-campaigns" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"><!--[if (gte mso 9)|(IE)]> <xml> <o:OfficeDocumentSettings> <o:AllowPNG/> <o:PixelsPerInch>96</o:PixelsPerInch> </o:OfficeDocumentSettings> </xml><![endif]--><!--[if (gte mso 9)|(IE)]> <style type="text/css"> body{width: 600px;margin: 0 auto;}table{border-collapse: collapse;}table, td{mso-table-lspace: 0pt;mso-table-rspace: 0pt;}img{-ms-interpolation-mode: bicubic;}</style><![endif]--> <style type="text/css"> body, p, div{font-family: arial,helvetica,sans-serif; font-size: 14px;}body{color: #000000;}body a{color: #1188E6; text-decoration: none;}p{margin: 0; padding: 0;}table.wrapper{width:100% !important; table-layout: fixed; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: 100%; -moz-text-size-adjust: 100%; -ms-text-size-adjust: 100%;}img.max-width{max-width: 100% !important;}.column.of-2{width: 50%;}.column.of-3{width: 33.333%;}.column.of-4{width: 25%;}#media screen and (max-width:480px){.preheader .rightColumnContent, .footer .rightColumnContent{text-align: left !important;}.preheader .rightColumnContent div, .preheader .rightColumnContent span, .footer .rightColumnContent div, .footer .rightColumnContent span{text-align: left !important;}.preheader .rightColumnContent, .preheader .leftColumnContent{font-size: 80% !important; padding: 5px 0;}table.wrapper-mobile{width: 100% !important; table-layout: fixed;}img.max-width{height: auto !important; max-width: 100% !important;}a.bulletproof-button{display: block !important; width: auto !important; font-size: 80%; padding-left: 0 !important; padding-right: 0 !important;}.columns{width: 100% !important;}.column{display: block !important; width: 100% !important; padding-left: 0 !important; padding-right: 0 !important; margin-left: 0 !important; margin-right: 0 !important;}.social-icon-column{display: inline-block !important;}}</style> </head> <body> <center class="wrapper" data-link-color="#1188E6" data-body-style="font-size:14px; font-family:arial,helvetica,sans-serif; color:#000000; background-color:#FFFFFF;"> <div class="webkit"> <table cellpadding="0" cellspacing="0" border="0" width="100%" class="wrapper" bgcolor="#FFFFFF"> <tr> <td valign="top" bgcolor="#FFFFFF" width="100%"> <table width="100%" role="content-container" class="outer" align="center" cellpadding="0" cellspacing="0" border="0"> <tr> <td width="100%"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td><!--[if mso]> <center> <table><tr><td width="600"><![endif]--> <table width="100%" cellpadding="0" cellspacing="0" border="0" style="width:100%; max-width:600px;" align="center"> <tr> <td role="modules-container" style="padding:0px 0px 0px 0px; color:#000000; text-align:left;" bgcolor="#FFFFFF" width="100%" align="left"><table class="module preheader preheader-hide" role="module" data-type="preheader" border="0" cellpadding="0" cellspacing="0" width="100%" style="display: none !important; mso-hide: all; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;"> <tr> <td role="module-content"> <p>I hope you have a great day today...</p></td></tr></table><table class="wrapper" role="module" data-type="image" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;" data-muid="64efa4d4-043b-4982-a412-9d010d10b043"> <tbody> <tr> <td style="font-size:6px; line-height:10px; padding:0px 0px 0px 0px;" valign="top" align="center"> <img class="max-width" border="0" style="display:block; color:#000000; text-decoration:none; font-family:Helvetica, arial, sans-serif; font-size:16px;" width="512" alt="" data-proportionally-constrained="true" data-responsive="false" src="http://cdn.mcauto-images-production.sendgrid.net/82cf15c98221d9d9/1cf0943b-5037-4305-bd81-551fb7d3e346/512x496.png" height="496"> </td></tr></tbody> </table></td></tr></table><!--[if mso]> </td></tr></table> </center><![endif]--> </td></tr></table> </td></tr></table> </td></tr></table> </div></center> </body> </html>',
};
await sgMail.send(msg);
})
);
}
} catch (e) {
console.log(e);
return `Error: ${e}`;
}
};

Related

How to send HTML email with SendGrid Rest API using custom html file with Nodejs handlebars?

I'm trying to send dynamic emails with Twilio SendGrid Rest API with Nodejs and handlebars. I have created my own custom template and placed the design in a file template.html. I'm successfully using this template using Nodemailer and SMTP-transport. But when trying to send it with SendGrid I get error :
ResponseError: Forbidden
at node_modules/#sendgrid/client/src/classes/client.js:146:29
at processTicksAndRejections (internal/process/task_queues.js:95:5) { code: 403, response: {
headers: {
server: 'nginx',
date: 'Wed, 07 Sep 2022 17:03:16 GMT',
'content-type': 'application/json',
'content-length': '281',
connection: 'close',
'access-control-allow-origin': 'https://sendgrid.api-docs.io',
'access-control-allow-methods': 'POST',
'access-control-allow-headers': 'Authorization, Content-Type, On-behalf-of, x-sg-elas-acl',
'access-control-max-age': '600',
'x-no-cors-reason': 'https://sendgrid.com/docs/Classroom/Basics/API/cors.html',
'strict-transport-security': 'max-age=600; includeSubDomains'
},
body: { errors: [Array] } } }
This is my nodejs
const handlebars = require('handlebars');
const path = require('path');
const fs = require('fs');
const sendgrid = require('#sendgrid/mail')
sendgrid.setApiKey(sendgrid_api_key);
//readhtmfile
var readHTMLFile = function (path, callback) {
fs.readFile(path, { encoding: 'utf-8' }, function (err, html) {
if (err) {
throw err;
callback(err);
}
else {
callback(null, html);
}
});
};
//dynamic variable received from client
var name = 'John Doe';
//email user
readHTMLFile(path.join(__dirname, '/', 'template.html'), function (err, html) {
var template = handlebars.compile(html);
var replacements = {
email_title: 'Welcome email',
email_body: 'Welcome to our website '+name
};
var htmlToSend = template(replacements);
var mailOptions = {
from: '"Company Website" <verified_sendgrid_email#company.com>', // sender address
to: email, // list of receivers
subject: "Welcome email ", // Subject line
html: htmlToSend, // html body
};
sendgrid.send(mailOptions, function (error, response) {
if (error) {
console.log(error);
} else {
console.log(response);
}
});
});
Upon printing the body errors, which I should have done, the detailed error was :
{
errors: [
{
message: 'The from address does not match a verified Sender Identity. Mail cannot be sent until this error is resolved. Visit https://sendgrid.com/docs/for-developers/sending-email/sender-identity/ to see the Sender Identity requirements',
field: 'from',
help: null
}
]
}
Unlike me, make sure you enter the Verified SendGrid mail. I had misspelled it.
Everything works like a charm now!
If you wonder what the template looks like and how to make it dynamic here it is :
template.html
<html>
<head>
<style>
#media only screen and (max-width: 600px) {
.main {
width: 320px !important;
}
.top-image {
width: 20px !important;
}
.inside-footer {
width: 320px !important;
}
table[class="contenttable"] {
width: 320px !important;
text-align: left !important;
}
td[class="force-col"] {
display: block !important;
}
td[class="rm-col"] {
display: none !important;
}
.mt {
margin-top: 15px !important;
}
*[class].width300 {width: 255px !important;}
*[class].block {display:block !important;}
*[class].blockcol {display:none !important;}
.emailButton{
width: 100% !important;
}
.emailButton a {
display:block !important;
font-size:18px !important;
}
}
.coupon {
border: 5px dotted #bbb;
width: 80%;
border-radius: 15px;
margin: 0 auto;
max-width: 600px;
}
.container {
padding: 2px 16px;
background-color: #f1f1f1;
}
.promo {
background: #ccc;
padding: 3px;
}
.expire {
color: red;
}
</style>
</head>
<body link="#00a5b5" vlink="#00a5b5" alink="#00a5b5">
<table class="main contenttable" align="center" style="font-weight: normal;border-collapse: collapse;border: 0;margin-left: auto;margin-right: auto;padding: 0;font-family: Arial, sans-serif;color: #555559;background-color: white;font-size: 16px;line-height: 26px;width: 600px;">
<tr>
<td class="border" style="border-collapse: collapse;border: 1px solid #eeeff0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 26px;">
<table style="font-weight: normal;border-collapse: collapse;border: 0;margin: 0;padding: 0;font-family: Arial, sans-serif;">
<tr>
<td colspan="4" valign="top" class="image-section" style="border-collapse: collapse;border: 0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 26px;background-color: #fff;border-bottom: none !important;">
<a href="https://mycompany.com">
<img class="top-image"
src="https://mycompany.com/images/webb_logo_.png"
style="line-height: 1;width: 100px;"
alt="My Company Logo">
</a>
</td>
</tr>
<tr>
<td valign="top" class="side title" style="border-collapse: collapse;border: 0;margin: 0;padding: 20px;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 26px;vertical-align: top;background-color: white;border-top: none;">
<table style="font-weight: normal;border-collapse: collapse;border: 0;margin: 0;padding: 0;font-family: Arial, sans-serif;">
<tr style="display: none !important;">
<td class="head-title" style="border-collapse: collapse;border: 0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 28px;line-height: 34px;font-weight: bold; text-align: center;">
<div class="mktEditable" id="main_title">
{{{email_title}}}
</div>
</td>
</tr>
<tr style="display: none !important;">
<td class="sub-title" style="border-collapse: collapse;border: 0;margin: 0;padding: 0;padding-top:5px;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 18px;line-height: 29px;font-weight: bold;text-align: center;">
<div class="mktEditable" id="intro_title">
{{{email_subtitle}}}
</div></td>
</tr>
<tr>
<td class="top-padding" style="border-collapse: collapse;border: 0;margin: 0;padding: 5px;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 26px;"></td>
</tr>
<tr>
<td class="grey-block" style="border-collapse: collapse;border: 0;margin: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 26px;background-color: #fff; text-align:center;">
<div class="mktEditable" id="cta">
<img class="top-image"
src="https://mycompany.com/images/learn.gif"
style="width:100% !important;" />
<br><br>
<a style="color:#000067;
background-color:#FCE8ED;
border: 10px solid #FCE8ED;
border-radius: 3px;
text-decoration:none;" href="https://mycompany.com/login.php">
Log In Your Account Now
</a>
</div>
</td>
</tr>
<tr>
<td class="top-padding" style="border-collapse: collapse;border: 0;margin: 0;padding: 15px 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 21px;">
<hr size="1" color="#eeeff0">
</td>
</tr>
<tr>
<td class="text" style="border-collapse: collapse;border: 0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 26px;">
<div class="mktEditable" id="main_text">
{{{email_body}}}
<br><br>
<span style="font-style: italic;">
<small>
<strong>
“ Build powerful and beautiful websites in 5 mins or less without coding ”
</strong>
</small>
</span>
</div>
</td>
</tr>
<tr>
<td style="border-collapse: collapse;border: 0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 24px;">
<br>
</td>
</tr>
<tr>
<td class="text" style="border-collapse: collapse;border: 0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 24px;">
<div class="mktEditable" id="download_button" style="text-align: center;">
</div>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="border-collapse: collapse;border: 0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 24px; padding: 20px;">
<div class="mktEditable" id="cta_try">
<table border="0" cellpadding="0" cellspacing="0" class="mobile" style="font-weight: normal;border-collapse: collapse;border: 0;margin: 0;padding: 0;font-family: Arial, sans-serif;">
<tr>
<td class="rm-col" style="border-collapse: collapse;border: 0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 24px;padding-right: 15px;"></td>
<td class="force-col" valign="top" style="border-collapse: collapse;border: 0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 24px;">
<table class="mb mt" style="font-weight: normal;border-collapse: collapse;border: 0;margin: 0;padding: 0;font-family: Arial, sans-serif;margin-bottom: 15px;margin-top: 0;">
<tr>
<td class="grey-block" style="border-collapse: collapse;border: 0;margin: 0;padding: 18px;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 24px;background-color: #fff; border-top: 3px solid #00a5b5; border-left: 1px solid #E6E6E6; border-right: 1px solid #E6E6E6; border-bottom: 1px solid #E6E6E6; width: 250px; text-align: center;">
<span style="font-family: Arial, sans-serif;
font-size: 24px;
line-height: 39px;
border-collapse: collapse;
border: 0;
margin: 0;
padding: 0;
-webkit-text-size-adjust: none;
color: #555559;
text-align: center;
font-weight: bold;">
Need Help?
</span>
<br>
My Company team is here to support you.
Visit our Help Center.<br><br>
<a style="color:#ffffff;
background-color: #00a5b5;
border-top: 10px solid #00a5b5;
border-bottom: 10px solid #00a5b5;
border-left: 20px solid #00a5b5;
border-right: 20px solid #00a5b5;
border-radius: 3px;
text-decoration:none;"
href="http://mycompany.com/contact.php">
Contact Us
</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</td>
</tr>
<tr bgcolor="#fff" style="border-top: 4px solid #00a5b5;">
<td valign="top" class="footer" style="border-collapse: collapse;border: 0;margin: 0;padding: 0;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 16px;line-height: 26px;background: #fff;text-align: center;">
<table style="font-weight: normal;border-collapse: collapse;border: 0;margin: 0;padding: 0;font-family: Arial, sans-serif;">
<tr>
<td class="inside-footer" align="center" valign="middle" style="border-collapse: collapse;border: 0;margin: 0;padding: 20px;-webkit-text-size-adjust: none;color: #555559;font-family: Arial, sans-serif;font-size: 12px;line-height: 16px;vertical-align: middle;text-align: center;width: 580px;">
<div id="address" class="mktEditable">
<b>
My Company Inc
<br>
Tech Support : 24/7/365
</b><br>
<a style="color: #00a5b5;"
href="https://mycompany.com">
Visit our website
</a>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

GET request works on local machine but doesn't work on Linux server

For the Discord bot, I need to send a GET request to a specific service to shorten a specific link.
I am using the https module from NPM to send a GET request, namely:
var https= require('https');
let opts = {
host: 'clicksfly.com',
path: '/api?api=SECRETCODEd&format=text&url=www.google.com',
method: 'GET'
};
const req = https.request(opts, res => {
res.on('data', d => {
console.log(d.toString());
});
});
req.end();
This code works completely on my computer, and it returns a shortcut link. However, on the server where my bot is located, this code does not work, namely, it sends a long code of an incomprehensible HTML page:
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA
-Compatible" content="IE=Edge,chrome=1" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Just a moment...</title>
<style type="text/css">
html, body {width: 100%; height: 100%; margin: 0; padding: 0;}
body {background-color: #ffffff; color: #000000; font-family:-apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, "Helvetica Neue",Arial, sans-serif; font-size: 16px; line-height: 1.7em;-webkit-font-smoothing: antialiased;}
h1 { text-align: center; font-weight:700; margin: 16px 0; font-size: 32px; color:#000000; line-height: 1.25;}
p {font-size: 20px; font-weight: 400; margin: 8px 0;}
p, .attribution, {text-align: center;}
#spinner {margin: 0 auto 30px auto; display: block;}
.attribution {margin-top: 32px;}
#keyframes fader { 0% {opacity: 0.2;} 50% {opacity: 1.0;} 100% {opacity: 0.2;} }
#-webkit-keyframes fader { 0% {opacity: 0.2;} 50% {opacity: 1.0;} 100% {opacity: 0.2;} }
#cf-bubbles > .bubbles { animation: fader 1.6s infinite;}
#cf-bubbles > .bubbles:nth-child(2) { animation-delay: .2s;}
#cf-bubbles > .bubbles:nth-child(3) { animation-delay: .4s;}
.bubbles { background-color: #f58220; width:20px; height: 20px; margin:2px; border-radius:100%; display:inline-block; }
a { co
lor: #2c7cb0; text-decoration: none; -moz-transition: color 0.15s ease; -o-transition: color 0.15s ease; -webkit-transition: color 0.15s ease; transition: color 0.15s ease; }
a:hover{color: #f4a15d}
.attribution{font-size: 16px; line-height: 1.5;}
.ray_id{display: block; margin-top: 8px;}
#cf-wrapper #challenge-form { padding-top:25px; padding-bottom:25px; }
#cf-hcaptcha-container { text-align:center;}
#cf-hcaptcha-container iframe { display: inline-block;}
</style>
<meta http-equiv="refresh" content="35">
<script type="text/javascript">
//<![CDATA[
(function(){
window._cf_chl_opt={
cvId: "2",
cType: "non-interactive",
cNounce: "24390",
cRay: "6c53b849cf342c52",
cHash: "d48c5950487c1fc",
cPMDTk: "TGRJIKcYNeQaUi4qjEFvtSSBAfHY03rt_7_2xESZg24-1640788159-0-gaNycGzNBuU",
cFPWv: "g",
cTTimeMs: "1000",
cRq: {
ru: "aHR0cHM6Ly9jbGlja3NmbHkuY29tL2FwaT9hcGk9Yjg4YjhjZDg5MjBmNzZjYTBhMDcwYmM1ZDQ2MmI5MWQ4NmNmMGI1ZCZmb3JtYXQ9dGV4dCZ1cmw9d3d3Lmdvb2dsZS5jb20=",
ra: "",
rm: "R0VU",
d: "47w2TkCdqOr0Tck9v6/aqzyT2lSjPuS81Akssy/HzRxaWwidLLHW74f1FOQUFn/lAWOf/De/txE6ePHyUXrUmXM3ltJ8BE5ZvBPCPF8n2muZ2XR33mqdLzTVcErGWEq0YeyjdXkgvNvZTVfkM70rOAHAYJb2suMmaUae91VBgKpIVnkw26Wwr7P9mFqluxpQREHJ+QAxC4CpNsMdQOYJD7GNYns
Pr+wFSJihZBiPymo8rx4Uegxcnf9sJhvItS7WDNrr5Eja/zEf4hnTasqLHeOknNIJ9np06y0fspnkEF6/qDgp4NSQdLEYV5pkbwXCqbEOfuBX3fGRuX0+qajK1exUUGPxLrzqL37mdD/fNA0wYhiDSZS2BHHlyler2S88M7vXBvLBNM78BQmVEan/CTnzck3sGqUgs40Ckhy4HEncspT7Lu87RPsqQ8kf/qiC8IDxLRDOGnJF5AThherCErcAv7zUi6gVr5bB5/qEW74Rp8c1Q1vwAImtYNC0SxPJ5LbgnUdOUeUhHUe0s5Rw4Dx7zIbHA9VpMpyAhemSaHA=",
t: "MTY0MDc4ODE1OS4wMTEwMDA=",
m: "f24BKfHcLktTTQE1Q1/kNNARn0oM+B4CwSSsUmvRs6g=",
i1: "+c9VZZ25U4G4BasL/L05rg==",
i2: "Kz28rQ4qA6UO6XV/AQmYsA==",
zh: "va4hCvZPZYx/dl/GK/fh92PoHUPArv8s552Q7x2/qYo=",
uh: "DV4j3Tmrbi5Rs1q3ahwVS6SgbPbI7np5884QO1u1Cgg=",
hh: "pl7IslarvVZvfg0YHKRLaukHlDa0TtpfuYJctN/tpqM=",
}
}
window._cf_chl_enter = function(){window._cf_chl_opt.p=1};
})();
//]]>
</script>
</head>
<body>
<table width="100%" height="100%" cellpadding="20">
<tr>
<td align="center" valign="middle">
<div class="cf-browser-verification cf-im-under-attack">
<noscript>
<h1 data-translate="turn_on_js" style="color:#bd2426;">Please turn JavaScript on and reload the page.</h1>
</noscript>
<div id="cf-content" style="display:none">
<div id="cf-bubbles">
<div class="bubbles"></div>
<div class="bubbles"></div>
<div class="bubbles"></div>
</div>
<h1><span dat
a-translate="checking_browser">Checking your browser before accessing</span> clicksfly.com.</h1>
<div id="no-cookie-warning" class="cookie-warning" data-translate="turn_on_cookies" style="display:none">
<p data-translate="turn_on_cookies" style="color:#bd2426;">Please enable Cookies and reload the page.</p>
</div>
<p data-translate="process_is_automatic">This process is automatic. Your browser will redirect to your requested content shortly.</p>
<p data-translate="allow_5_secs" id="cf-spinner-allow-5-secs" >Please allow up to 5 seconds…</p>
<p data-translate="redirecting" id="cf-spinner-redirecting" style="display:none">Redirecting…</p>
</div>
<form class="challenge-form" id="challenge-form" action="/api?api=b88b8cd8920f76ca0a070bc5d462b91d86cf0b5d&format=text&url=www.google.com&__cf_chl_f_tk=TGRJIKcYNeQaUi4qjEFvtSSBAfHY03rt_7_2xESZg24-1640788159-0-gaNycGzNBuU" method="POST" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="md" value="xkEcrpi8t1.QjXZlqCsIjpdEGmDY_IdcgbTeOQYnWyM-1640788159-0-AVJqqT9Tvcgthj9NRbMs79IOh1RWvyCKlp7aD5F_0fTulpLPDbF-RLTYMcO9QsWjbBGbgh_Wc6nalQ5OfQ5AfETkxDG89DCtXBs8eS12TTViPp2xtMEUwLQfccIK6xA-lcZ4eYMUD7iGkWMVnLq0WPsKybj52VXST_RhKTB-_CYc8HLABUkmygvc7bzMkoratKKK7jNCM_kV2ROIF-sxykIOseW9Qzg7-8xGIN55DCtQdF-AGg6P5EZPgZ--6fgAXmpDOt6HdnUfRXOy
sjKKD1m0LEswX3mcqY2AQnh1ocfg4rXbBy7FwTX2SHRb0qWbQ96DC5Jw6uq4NuqzYdbTiRNx_jq2Kujxhu5F74LpJQfxBR13hujaoqODdBxhbl3m-X9EzNNloGdNgK5ahkTD9BtUPMaYL_bsygKJXLtlkq7sUsGB3OxPsKFFb87UfgaSWXTc0HrXoRXoa1f91kRM02RyBnbOzu6eV4BA0-hfaW0n3oO7LkKoSbXuibYYst4Y1I21_-BxrFE5r23okOcM698KGlACH9TzAbBmEx0H_k1P1J99RPV4od1oBfQrDCbfE6Hwehaj77g63-NwfMUtweEEG_Iegj-7gJIsmTdpGqENcIgZzBkVWJoQyJtmkvkQSRqBGrauqvLZuUpT4J2JcwRwPs-ybpK7WKKzRyOA2vK2UrrjRpQrhIhqj7ay7Cz1eWiyJXnwPvzu3wRfE5t3CHMU0od5eKuEdh0Ruq1y6Tj7n22ho9sn92vPwWkVdk9CeT101bJ83LRrJk3XPvIOi1E" />
<input type="hidden" name="r" value="EfcTylAJ6D0BDns4eSFtNCPUpLdh4A7kjPglrCzMQeo-1640788159-0-AanhkUrahNV4ONtYb+sTo+uauUtmeERPrcNryzlJIFlv4alUyU7Lhm1SHiFYP9lTDLGxy6PM9+uYgtQ3AXWBqoUr39qaO6Kto/d9EArJN8X52JJkzrLUVcoj//vu++QxzuTIsT0NhOLdCTIYZzGxDsCSzhYEIQ8iGpN8u+eBdcBgQkvZUNlETgynelJUNpjv5x3CX9nfBo0C/WlEjYWhC++TP68liuZatG0bIA2uxXOfopNCMch5xtiulF9GYMafWhIwxVM1+LHYAscRN+PUhZluA1+6tpkLyMneVRry2+3LA0I3zRET0Vq/5Z+MYRrwLU7XdpAWqDyFQPN/YsG4V5qWdwX2NKsLRzP6dxwbvrX14NFpP6Xrsj8Dr9PAs1zPce2gETT3Wv5LpDeUbX9k/Tlf1IkLhLse2Kx0giwa9dI5vEZb1SavlGYkGKUXPJmc80gocm+WvZVUcNiXbkLnlXixbbCcKQzLMK1e9rZIrLJv7kuzlIar/hd9A7otR5+I5iUIUnnnyWLJjuYcnN3+c9W9r0clCPtT+GpMAPkjz5boWU1PgJbUEH8JpFicCDy9cJcui+VXNe1b6GQgSwPZl0ABjzTqfWxVWjgxYnA1Jz+euFT2BSlEIvGg2Mhj4bJNa2RcbwmnBT3stMObWg3JS9IivnBZmkUsprWiPr07qr/FAWSRpjYpykmCp7CEgssEKbGwk7fUc43RlJclVKyW8R00JN7BpQH/44TwKPrKN9G
i4XW39lPLJP0SjoVu73QAqssV/D2bHtEJ2DDJ5mmt62lp8ukiMw9XBqmm6slygREwvx8gmaAm1vt3FV7TXD5goI17r1yPWGqww0s46+py2bhaWq4fcVmzZ6nDoTdPmF49A47zBcOXCRPKRiX33eL+nYZnQ1LH7IFfgqtu8YWaDjkVGzCyTHnGVOYTr2XVhNAAjLmi/nW4kJgVzrufS+Is26NxpbjMXWtBjkFTrYE+r+E7tqhSOmlLPIQxVpX0dfoXd3XOiBTV2GO5pGgHJCEVcDGufUQvguiogLwkV1zBlu29lfsrSjfhKvJjH28nFL3v+HPBhXOrPelN2xtrSlHXmoRtTCA9e075lZUOFMBpjBPGCw2uZD2i/pHVtFwa+0p63AgqnGF/IrDnVuaFs165kMpGnHumggU5ZK5XqAIYwKmr106mK6QjmOx5WDd6oc0WsRYVfpVwQB4P+8jWf9VAl6PfFBhQKzqwj5G0mQDcrhUfx8rknzjr78Nh6Bv51ZXUtNL1y76XMwhsN+6Cu2T1Ms1r+eSdRgo6LpueBF0pr6mA/xUIQXgP4P6j0C9dRPH/MhsdJmKiDv925ju7+xcFRsDILdZ7vsae69tDN04q0d4sBzKvOmMsIxWiikr9P4D7XvB5RTnwGQ9a7XILf0q8jZmEtLeMV9qfY3AzYFvvi/m3zGMZmNbFNkyg1PvJfIRGch7vUfFXqT5YYgJZ7M9gBN4yLxC+WtP1UKmoOHd+cQg9xzeTNxuvQDM/yjMynW0uxZlxtdL4Ucp4PtHhKWvjNg7LIJB6niNAqeDMsBLov6F1P+QLs4GVdS1fRtpgnmxHN/+y3/V6g/9/Eb/trYmWC+3e2pD1DIAYw7BUjhyo+KRPjDKXUR2CqC0nQjp8Q7uOOfT+JK9uuONsiXfcE0SucL4K6r1UvDmT/qXxPNwtt5hIzTmbuaJ63HV+Urh49m07"/>
<input type="hidden" value="133b40e5940ea08e8901277e08bc72e4" id="jschl-vc" name="jschl_vc"/>
<!-- <input type="hidden" value="" id="jschl-vc" name="jschl_vc"/> -->
<input type="hidden" name="pass" value="1640788160.011-Z8znjbzNhw"/>
<input type="hidden" id="jschl-answer" name="jschl_answer"/>
</form>
<script type="text/javascript">
//<![CDATA[
(function(){
var a = document.getElementById('cf-content');
a.style.display = 'block';
var isIE = /(MSIE|Trident\/|Edge\/)/i.test(window.navigator.userAgent);
var trkjs = isIE ? new Image() : document.createElement('img');
trkjs.setAttribute("src", "/cdn-cgi/images/trace/jschal/js/transparent.gif?ray=6c53b849cf342c52");
trkjs.id = "trk_jschal_js";
trkjs.setAttribute("alt", "");
document.body.appendChild(trkjs);
var cpo=document.createElement('script');
cpo.type='text/javascript';
cpo.src="/cdn-cgi/challenge-platform/h/g/orchestrate/jsch/v1?ray=6c53b849cf342c52";
if (window._cf_chl_opt.cPMDTk && window.history && window.history.replaceState && window.URLSearchParams) {
var ogU = location.pathname + location.search + location.hash;
var p = new URLSearchParams(location.search);
p.set('__cf_chl_rt_tk', window._cf_chl_opt.cPMDTk);
history.replaceState(null, null, location.pathname + '?' + p.toString() + location.hash);
cpo.onload = function() {
history.replaceState(null, null, ogU);
};
}
document.getElementsByTagName('head')[0].appendChild(cpo);
}());
//]]>
</script>
<div id="trk_jschal_nojs" style=
"background-image:url('/cdn-cgi/images/trace/jschal/nojs/transparent.gif?ray=6c53b849cf342c52')"> </div>
</div>
<div style="display: none;">table</div>
<div class="attribution">
DDoS protection by <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing/" target="_blank">Cloudflare</a>
<br />
<span class="ray_id">Ray ID: <code>6c53b849cf342c52</code></span>
</div>
</td>
</tr>
</table>
</body>
</html>
I tried to use CURL instead of modules, however the same problem occurred with it, but that did not lead me to a possible solution, and also tried to use other modules to send the request, however with them the same problem.
Also, I found out that this HTML code is associated specifically with the site of the link shortening service, but, as you understand, I want to refer to the service API.

Element found using Selenium expected conditions but doesn't appear in the page source

The page I'm trying to scrape is http://zipatlas.com/us/oh/zip-code-comparison/population-below-poverty-level.1.htm
It loads some content through javascript, so I'm trying to use the expected_conditions module in selenium to detect it. What happens is that I apparently detect the element I'm looking for, but when I print the page source, it doesn't contain that element. There's a link labeled "TEST LINK" at the bottom of the page, so I figured if that has loaded, the rest of the page pretty much has also.
Here is my code:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
curr_url = r"http://zipatlas.com/us/oh/zip-code-comparison/population-below-poverty-level.1.htm"
driver = webdriver.Firefox()
driver.get(curr_url)
try:
myElem = WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.LINK_TEXT, 'TEST LINK')))
except TimeoutException:
print("took too long to load")
print("element detected")
elem = driver.find_element_by_link_text('TEST LINK')
html = elem.get_attribute("outerHTML")
print(html)
print(driver.page_source)
driver.close()
I do successfully print out the detected element as TEST LINK
However, in the page_source that is printed out, I cannot find this. The page source is located here. I also tried using other expected_conditions like element_to_be_clickable
So my question is why is the located element not appearing in the page source? Also, is there any other way to detect that the whole page has loaded? Using expected_conditions is really the only potential solution I found.
You were close. Before you exract the outerHTML of the WebElement you need to induce WebDriverWait.
You can use the following solution:
Code Block:
driver.get('http://zipatlas.com/us/oh/zip-code-comparison/population-below-poverty-level.1.htm')
print(WebDriverWait(driver, 30).until(EC.element_to_be_clickable((By.LINK_TEXT, 'TEST LINK'))).get_attribute("outerHTML"))
print("==========")
print(driver.page_source)
Console Output:
TEST LINK
==========
<html><head><title>
Zip Codes with the Highest Percentage of Population Below Poverty Level in Ohio | Zip Atlas
</title>
<meta name="robots" content="all,index,follow"><meta name="rating" content="general"><meta name="author" content="ZipAtlas.com Development Team"><meta name="language" content="en-us"><meta name="copyright" content="Copyright 2011 ZipAtlas.com"><meta name="revisit-after" content="7 Days"><meta http-equiv="Expires" content="-1"><meta http-equiv="Distribution" content="Global"><meta http-equiv="Content-Type" content="text/html; charset=windows-1252"><meta name="google-site-verification" content="3cRw56ihbmZI3sma1cdmLLpkwcJEE_L1tUFYhaet2xQ">
<style type="text/css">
body, td, div, span, p { color: #333333; font-size: 12px; font-family: 'Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; }
select { color: #333333; font-size: 12px; font-family: 'Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; border: solid 1px #5A81A6; }
a { text-decoration: none; color: #0000D0; }
a:hover { text-decoration: underline; color: #0000D0; }
h1 { margin:0px 0px 10px 0px; padding:0px 0px 0px 0px; font-family: 'Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; font-size: 16px; font-weight: normal; color: #3d7795;}
h2 { margin:35px 0px 0px 0px; padding:0px 0px 0px 0px; font-family: 'Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; font-size: 15px; font-weight: normal; color: #3d7795;}
h3 { margin:35px 0px 0px 0px; padding:0px 0px 0px 0px; font-family: 'Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; font-size: 14px; font-weight: normal; color: #3d7795;}
span.link { cursor: pointer; text-decoration: none; font-size: 12px; font-family: 'Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif; color: #0000D0; }
span.link:hover { cursor: pointer; text-decoration: underline; color: #0000D0; }
td.report_header { border: solid 1px #5A81A6; background-color: #5A81A6; color: #ffffff; }
td.report_data { border: solid 1px #5A81A6; padding: 1px 5px 1px 5px; font-size: 12px; }
</style>
<link rel="preload" href="https://adservice.google.co.in/adsid/integrator.js?domain=zipatlas.com" as="script"><script src="https://partner.googleadservices.com/gampad/cookie.js?domain=zipatlas.com&callback=_gfp_s_&client=ca-pub-7710991166856237"></script><script src="https://pagead2.googlesyndication.com/pagead/js/r20200624/r20190131/show_ads_impl_fy2019.js" id="google_shimpl"></script><script type="text/javascript" src="https://adservice.google.co.in/adsid/integrator.js?domain=zipatlas.com"></script><link rel="preload" href="https://adservice.google.com/adsid/integrator.js?domain=zipatlas.com" as="script"><script type="text/javascript" src="https://adservice.google.com/adsid/integrator.js?domain=zipatlas.com"></script><script src="https://www.google.com/cse/static/element/57975621473fd078/cse_element__en.js?usqp=CAI%3D" type="text/javascript"></script><link type="text/css" rel="stylesheet" href="https://www.google.com/cse/static/element/57975621473fd078/default_v2+en.css"><link type="text/css" rel="stylesheet" href="https://www.google.com/cse/static/style/look/v4/default.css"></head>
<body style="margin:0px 0px 0px 0px; padding: 0px 0px 0px 0px; background: url('/images/bg.gif');">
<table cellpadding="0" cellspacing="0" style="width:100%;">
<tbody><tr>
<td style="background: url('/images/shadow-left.gif') top right repeat-y;" valign="top">
<table cellpadding="0" cellspacing="0" style="width:100%;height:200px; background: url('/images/bg-top-left.gif') top right no-repeat;">
<tbody><tr>
<td> </td>
</tr>
</tbody></table>
</td>
<td style="width:930px;background:url('/images/bg-top.gif') top left repeat-x;" valign="top">
<table cellpadding="0" cellspacing="0" style="width:100%;">
<tbody><tr>
<td>
<table cellpadding="0" cellspacing="0" style="width:100%;">
<tbody><tr>
<td>
<img border="0" src="/images/logo.gif" alt="ZipAtlas Home">
</td>
</tr>
</tbody></table>
</td>
<td align="right" valign="bottom" style="color: #c0c0c0; padding-bottom: 3px; font-size: 13px;">
<a style="color: #ffffff;" href="/downloads/">Database Download</a>
</td>
</tr>
</tbody></table>
<table cellpadding="0" cellspacing="0" style="width:100%; background-color:#ffffff;">
<tbody><tr>
<td style="padding: 10px 10px 10px 10px; height:550px;" valign="top">
<!--<form action="/" method="get">//-->
<table cellpadding="0" cellspacing="0" style="width:100%; border-bottom: solid 1px #f0f5f9;">
<tbody><tr>
<td><h1>Zip Codes with the Highest Percentage of Population Below Poverty Level in Ohio</h1></td>
<td align="right" valign="top">
<table cellpadding="0" cellspacing="0">
<tbody><tr>
<td><img border="0" src="/images/social/facebook-s.gif"></td>
<td style="padding-left:1px;"><img border="0" src="/images/social/twitter-s.gif"></td>
<td style="padding-left:1px;"><img border="0" src="/images/social/myspace-s.gif"></td>
<!--<td style="padding-left:15px;"><input type="text" name="q" style="width:175px;" value="" /></td>
<td><input type="submit" value="Search" /></td>//-->
</tr>
</tbody></table>
</td>
</tr>
</tbody></table>
<!--</form>//-->
<table cellpadding="0" cellspacing="0" style="width:100%; border-bottom: solid 1px #f0f5f9;">
<tbody><tr>
<td style="padding:15px 0px 10px 0px;" align="center">
<script type="text/javascript" async="" src="https://cse.google.com/cse.js?cx=013012024412622983838:nucmfhluwdu"></script><script>
(function () {
var cx = '013012024412622983838:nucmfhluwdu';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
})();
</script>
<gcse:search></gcse:search>
</td>
</tr>
</tbody></table>
<table cellpadding="0" cellspacing="0" style="width:100%; border-bottom: solid 1px #f0f5f9">
<tbody><tr>
<td style="padding:5px 0px 5px 0px;" align="center">
<script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- ZipAtlas - 3 Across (Mixed) -->
<ins class="adsbygoogle" style="display:inline-block;width:300px;height:250px" data-ad-client="ca-pub-7710991166856237" data-ad-slot="2630863889" data-adsbygoogle-status="done"><ins id="aswift_0_expand" style="display:inline-table;border:none;height:250px;margin:0;padding:0;position:relative;visibility:visible;width:300px;background-color:transparent;"><ins id="aswift_0_anchor" style="display:block;border:none;height:250px;margin:0;padding:0;position:relative;visibility:visible;width:300px;background-color:transparent;"></ins></ins></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</td>
<td style="padding:5px 0px 5px 0px;" align="center">
<script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- ZipAtlas - 3 Across (Mixed) -->
<ins class="adsbygoogle" style="display:inline-block;width:300px;height:250px" data-ad-client="ca-pub-7710991166856237" data-ad-slot="2630863889" data-adsbygoogle-status="done"><ins id="aswift_1_expand" style="display:inline-table;border:none;height:250px;margin:0;padding:0;position:relative;visibility:visible;width:300px;background-color:transparent;"><ins id="aswift_1_anchor" style="display:block;border:none;height:250px;margin:0;padding:0;position:relative;visibility:visible;width:300px;background-color:transparent;"></ins></ins></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</td>
<td style="padding:5px 0px 5px 0px;" align="center">
<script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- ZipAtlas - 3 Across (Mixed) -->
<ins class="adsbygoogle" style="display:inline-block;width:300px;height:250px" data-ad-client="ca-pub-7710991166856237" data-ad-slot="2630863889" data-adsbygoogle-status="done"><ins id="aswift_2_expand" style="display:inline-table;border:none;height:250px;margin:0;padding:0;position:relative;visibility:visible;width:300px;background-color:transparent;"><ins id="aswift_2_anchor" style="display:block;border:none;height:250px;margin:0;padding:0;position:relative;visibility:visible;width:300px;background-color:transparent;"></ins></ins></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</td>
</tr>
</tbody></table>
<div id="ctl00_ContentPlaceHolder1_final_content" style="padding-top:10px;">
<table cellpadding="0" cellspacing="0">
<tbody><tr>
<td style="padding-left:3px;">Ohio Report:</td>
<td style="padding-left:5px;">
<div style="border: solid 1px #5A81A6; cursor:pointer; padding: 1px 5px 1px 5px; background-color: #FFFFD0; color: #5A81A6;" onmouseover="this.style.backgroundColor='#5A81A6';this.style.color='#ffffff';" onmouseout="this.style.backgroundColor='#FFFFD0';this.style.color='#5A81A6';" onclick="onContextMenu(event);" title="Click to select a different Ohio report">
Percentage of Population Below Poverty Level
</div>
</td>
</tr>
</tbody></table>
<td style="background: url('/images/shadow-right.gif') top left repeat-y;" valign="top">
<table cellpadding="0" cellspacing="0" style="width:100%;height:200px; background: url('/images/bg-top-right.gif') top left no-repeat;">
<tbody><tr>
<td> </td>
</tr>
</tbody></table>
</td>
</tr>
<tr>
<td align="right"><img src="/images/shadow-ll.gif"></td>
<td style="background: url('/images/edge-bottom.gif') top left repeat-x;">
<table cellpadding="0" cellspacing="0" style="width:100%;">
<tbody><tr><td><img src="/images/shadow-lr.gif"></td>
<td align="right"><img src="/images/shadow-rl.gif"></td>
</tr></tbody></table>
</td>
<td><img src="/images/shadow-rr.gif"></td>
</tr>
</tbody></table>
<center>
<div style="color:#c0c0c0; padding: 50px 0px 50px 0px;">
<a style="color: #ffffff;" href="/">Zip Atlas Home</a> |
<a style="color: #ffffff;" href="/downloads/">Downloads</a> |
<a style="color: #ffffff;" href="https://ecovinyl.ca">ecoVinyl</a> |
TEST LINK
<br><br>
<font color="#ffffff">© 2020 ZipAtlas.Com</font>
</div>
</center>
<script type="text/javascript">
function Set(el_name, c)
{
var el = document.getElementById(el_name);
if (el)
{
el.innerHTML = c;
}
}
function Show(el_name)
{
var el = document.getElementById(el_name);
if (el)
{
el.style.display = '';
}
}
function Hide(el_name)
{
var el = document.getElementById(el_name);
if (el)
{
el.style.display = 'none';
}
}
</script>
<!-- expo-MAX Code Start //-->
<!-- Paste this code into every page that you would like to track //-->
<script type="text/javascript">
document.write(unescape('%3Cscript type="text/javascript" src="'+document.location.protocol+'//expo-max.com/adserver/js/"%3E%3C/script%3E'));
</script><script type="text/javascript" src="http://expo-max.com/adserver/js/"></script>
<script type="text/javascript">
expomax_trace('WunfWYG%2bFajQ%2f9F4kqiaXg%3d%3d','cb959e484ba8457ca327aeefce4cb2b4');
</script><div id="g5ef264d7a54140f7b03eff0ea8cfe256" style="display:none;"><iframe style="display:none;" src="https://expo-max.com/adserver/track/?e=WunfWYG%2bFajQ%2f9F4kqiaXg%3d%3d&a=Mozilla%2F5.0%20(Windows%20NT%2010.0%3B%20Win64%3B%20x64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F83.0.4103.116%20Safari%2F537.36&l=http%3A%2F%2Fzipatlas.com%2Fus%2Foh%2Fzip-code-comparison%2Fpopulation-below-poverty-level.1.htm&r=&w=1366&h=768&p=http:"></iframe></div>
<!-- expo-MAX Code End //-->
<ins class="adsbygoogle adsbygoogle-noablate" data-adsbygoogle-status="done" style="display: none !important;"><ins id="aswift_3_expand" style="display:inline-table;border:none;height:0px;margin:0;padding:0;position:relative;visibility:visible;width:0px;background-color:transparent;"><ins id="aswift_3_anchor" style="display:block;border:none;height:0px;margin:0;padding:0;position:relative;visibility:visible;width:0px;background-color:transparent;"></ins></ins></ins></body><iframe id="google_esf" name="google_esf" src="https://googleads.g.doubleclick.net/pagead/html/r20200624/r20190131/zrt_lookup.html#" data-ad-client="ca-pub-7710991166856237" style="display: none;"></iframe></html>

How add, delete, edit and save functions will work on multiple tables in HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Bootstrap Table with Add and Delete Row Feature</title>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto|Varela+Round|Open+Sans"
/>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/icon?family=Material+Icons"
/>
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style type="text/css">
body {
color: #404e67;
background: #f5f7fa;
font-family: "Open Sans", sans-serif;
}
.table-wrapper {
width: 700px;
margin: 30px auto;
background: #fff;
padding: 20px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
}
.table-title {
padding-bottom: 10px;
margin: 0 0 10px;
}
.table-title h2 {
margin: 6px 0 0;
font-size: 22px;
}
.table-title .add-new {
float: right;
height: 30px;
font-weight: bold;
font-size: 12px;
text-shadow: none;
min-width: 100px;
border-radius: 50px;
line-height: 13px;
}
.table-title .add-new i {
margin-right: 4px;
}
table.table {
table-layout: fixed;
}
table.table tr th,
table.table tr td {
border-color: #e9e9e9;
}
table.table th i {
font-size: 13px;
margin: 0 5px;
cursor: pointer;
}
table.table th:last-child {
width: 100px;
}
table.table td a {
cursor: pointer;
display: inline-block;
margin: 0 5px;
min-width: 24px;
}
table.table td a.add {
color: #27c46b;
}
table.table td a.edit {
color: #ffc107;
}
table.table td a.delete {
color: #e34724;
}
table.table td i {
font-size: 19px;
}
table.table td a.add i {
font-size: 24px;
margin-right: -1px;
position: relative;
top: 3px;
}
table.table .form-control {
height: 32px;
line-height: 32px;
box-shadow: none;
border-radius: 2px;
}
table.table .form-control.error {
border-color: #f50000;
}
table.table td .add {
display: none;
}
</style>
<script type="text/javascript">
$(document).ready(function () {
$('[data-toggle="tooltip"]').tooltip();
var actions = $("table td:last-child").html();
// Append table with add row form on add new button click
$(".add-new").click(function () {
$(this).attr("disabled", "disabled");
var index = $("table tbody tr:last-child").index();
var row =
"<tr>" +
'<td><input type="text" class="form-control" name="current shift" id="cur_shft"></td>' +
'<td><input type="text" class="form-control" name="name current" id="n_curr"></td>' +
'<td><input type="text" class="form-control" name="shift handedover" id="shft_hndover"></td>' +
'<td><input type="text" class="form-control" name="name next" id="n_next"></td>' +
'<td><input type="text" class="form-control" name="time" id="shft_time"></td>' +
"<td>" +
actions +
"</td>" +
"</tr>";
$("table").append(row);
$("table tbody tr")
.eq(index + 1)
.find(".add, .edit")
.toggle();
$('[data-toggle="tooltip"]').tooltip();
});
// Add row on add button click
$(document).on("click", ".add", function () {
var empty = false;
var input = $(this).parents("tr").find('input[type="text"]');
input.each(function () {
if (!$(this).val()) {
$(this).addClass("error");
empty = true;
} else {
$(this).removeClass("error");
}
});
$(this).parents("tr").find(".error").first().focus();
if (!empty) {
input.each(function () {
$(this).parent("td").html($(this).val());
});
$(this).parents("tr").find(".add, .edit").toggle();
$(".add-new").removeAttr("disabled");
}
});
// Edit row on edit button click
$(document).on("click", ".edit", function () {
$(this)
.parents("tr")
.find("td:not(:last-child)")
.each(function () {
$(this).html(
'<input type="text" class="form-control" value="' +
$(this).text() +
'">'
);
});
$(this).parents("tr").find(".add, .edit").toggle();
$(".add-new").attr("disabled", "disabled");
});
// Delete row on delete button click
$(document).on("click", ".delete", function () {
$(this).parents("tr").remove();
$(".add-new").removeAttr("disabled");
});
});
</script>
</head>
<body>
<div class="container">
<div class="table-wrapper">
<div class="table-title">
<div class="row">
<div class="col-sm-8">
<h2><b>Shift Information</b></h2>
</div>
<div class="col-sm-4">
<button type="button" class="btn btn-info add-new">
<i class="fa fa-plus"></i> Add New
</button>
</div>
</div>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>Current Shift</th>
<th>Associates in Current Shift</th>
<th>Shift Handedover to</th>
<th>Associates in Next shift</th>
<th>Shift Handover time</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>First</td>
<td>Chandu</td>
<td>Second</td>
<td>Venkata</td>
<td>15:30</td>
<td>
<a class="add" title="Add" data-toggle="tooltip"
><i class="material-icons"></i></a
>
<a class="edit" title="Edit" data-toggle="tooltip"
><i class="material-icons"></i></a
>
<a class="delete" title="Delete" data-toggle="tooltip"
><i class="material-icons"></i></a
>
</td>
</tr>
<tr>
<td>Second</td>
<td>Venkata</td>
<td>Third</td>
<td>Mallikharjuna</td>
<td>23:00</td>
<td>
<a class="add" title="Add" data-toggle="tooltip"
><i class="material-icons"></i></a
>
<a class="edit" title="Edit" data-toggle="tooltip"
><i class="material-icons"></i></a
>
<a class="delete" title="Delete" data-toggle="tooltip"
><i class="material-icons"></i></a
>
</td>
</tr>
<tr>
<td>Third</td>
<td>Mallikharjuna</td>
<td>First</td>
<td>Saikiran</td>
<td>06:30</td>
<td>
<a class="add" title="Add" data-toggle="tooltip"
><i class="material-icons"></i></a
>
<a class="edit" title="Edit" data-toggle="tooltip"
><i class="material-icons"></i></a
>
<a class="delete" title="Delete" data-toggle="tooltip"
><i class="material-icons"></i></a
>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
I have created 6 html tables. I have written JS script for add, delete, edit and save functions. Now if i click on the add button for one table, the row is getting added 6 times to all tables. Please help on how to resolve this. Above example code is one such table and I just cloned the table to 5 other html files. I just changed the row column names

Why is gmail client (via Chrome and Android app) still strip <style> tag from HTML email?

I recently reviewed the Pluralsight course on HTML email and then made a sample for myself. I tested it through Mailchimp and the Mailchimp test environment renders it as expected for both mobile and desktop, but when I sent a test email to myself, both gmail clients that I use (Gmail app through Chrome on desktop and Android app on mobile) appeared to strip the style and link tags, in particular stripping the media screen size queries and associated classes, as well as font imports.
This article claims that gmail clients are now accepting tags, at least on most platforms, including the two I am testing. However, as noted the #media and #import queries are not working. (1) Is there something obviously wrong with my code?, or (2) is this an issue with Mailchimp?
HTML email code, and part of
<!DOCTYPE html>
<html lang="en">
<head>
<title>Happy Holidays!</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<link href="https://fonts.googleapis.com/css?family=Cabin|Libre+Baskerville|Pacifico" rel="stylesheet">
<style type="text/css">
/* CLIENT-SPECIFIC STYLES ------------------- */
#outlook a {
padding: 0; /* Force Outlook to provide a "view in browser" message */
}
.ReadMsgBody {
width: 100%; /* Force Hotmail to display emails at full width */
}
.ExternalClass {
width:100%; /* Force Hotmail to display emails at full width */
}
.ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {
line-height: 100%; /* Force Hotmail to display normal line spacing */
}
body, table, td, a { /* Prevent WebKit and Windows mobile changing default text sizes */
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table, td { /* Remove spacing between tables in Outlook 2007 and up */
mso-table-lspace: 0pt;
mso-table-rspace:0pt;
}
img { /* Allow smoother rendering of resized image in Internet Explorer */
-ms-interpolation-mode: bicubic;
}
/* RESET STYLES --------------------------- */
body {
height: 100% !important;
margin: 0;
padding: 0;
width: 100% !important;
}
img {
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
}
table {
border-collapse: collapse !important;
}
a {
text-decoration: none;
}
/* iOS BLUE LINKS */
.apple-links a {
color: #A50001;
text-decoration: none;
}
/* FONTS */
#import url('https://fonts.googleapis.com/css?family=Cabin|Libre+Baskerville|Pacifico');
/* MOBILE STYLES ------------------------ */
#media only screen and (max-width: 600px) {
td[class="logo"] img {
margin: 0 auto !important;
}
table[class="wrapper"] {
width: 100% !important;
}
td[class="mobile-image-pad"] {
padding: 0 10px 0 10px !important;
}
td[class="mobile-title-pad"] {
padding: 10px 0px 0px 10px !important;
}
td[class="mobile-text-pad"] {
padding: 10px 10px 10px 10px !important;
}
td[class="mobile-column-right"] {
padding-top: 20px !important;
}
img[class="fluid-image"] {
width: 100% !important;
height: auto !important;
}
td[class="hide"] {
display: none !important;
}
td[class="mobile-button"] {
padding: 12px 60px 12px 60px !important;
}
td[class="mobile-button"] a {
font-size: 24px !important;
}
}
</style>
</head>
<body style="margin: 0; padding: 0;" >
<!-- CONTAINER TABLE (HEADER) -->
<table border="0" cellpadding="0" cellspacing="0" width="100%" style=" table-layout: fixed;">
<tr>
<td align="center" bgcolor="#339969" style="padding: 0 0 0 0;">
<!-- HIDDEN PREHEADER -->
<div style="display: none; font-size: 1px; color:#333333; line-height: 1px; font-family: Arial, sans-serif; max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden; mso-hide: all;">
Preheader inbox text
</div>
<!-- WRAPPER TABLE -->
<table border="0" cellpadding="0" cellspacing="0" width="100%" class="wrapper">
<!-- HEADER -->
<tr>
<td>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td align="left" background="img/url" alt="Bappy Bolidays!" width="100%" height="100" style="background-size:contain;">
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- CONTAINER TABLE (HERO) -->
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;">
<tr>
<td align="center" bgcolor="#C3D79C" style="padding: 20px 0 20px 0;">
<!-- WRAPPER TABLE -->
<table border="0" cellpadding="0" cellspacing="0" width="600" class="wrapper">
<tr>
<td>
<!-- TWO COLUMNS -->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td>
<!-- LEFT COLUMN -->
<table border="0" cellpadding="0" cellspacing="0" width="64%" align="left" class="wrapper">
<tr>
<td>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td class="mobile-image-pad">
<img src="img/url" alt="Two Beautiful Peeps" width="384" height="288" border="0" style="display: block; image-orientation: from-image; color: #A50001; font-family: Arial, sans-serif; font-weight: bold; font-size: 24px; background-color: #339969; -webkit-border-radius: 4px; border-radius: 4px;" class="fluid-image" />
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- RIGHT COLUMN -->
<table border="0" cellpadding="0" cellspacing="0" width="30%" align="right" class="wrapper">
<tr>
<td valign="middle" height="100%">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td align="center" style="color: #A50001; font-family: 'Libre Baskerville', serif; font-weight: bold; font-size: 32px; line-height: 38px; text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);" class="mobile-title-pad">
Title
</td>
</tr>
<tr>
<td align="center" style="color: #339969; font-family: 'Cabin', sans-serif; font-weight: bold; font-size: 20px; line-height: 24px;" class="mobile-title-pad">
from
</td>
</tr>
<tr>
<td align="center" style="color: #A50001; font-family: 'Libre Baskerville', serif; font-weight: bold; font-size: 32px; line-height: 38px; text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);" class="mobile-title-pad">
Title
</td>
</tr>
<tr>
<td align="center" style="padding: 20px 0 0 0;">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td align="center" bgcolor="#339969" style="padding: 12px 18px 12px 18px; -webkit-border-radius:3px; border-radius:3px; -webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); -moz-box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);" class="mobile-button">
let's go champ →
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- CONTAINER TABLE (VIGNETTES) -->
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;">
<tr>
<td align="center" bgcolor="#fff2f9" style="padding: 40px 0 40px 0;">
<!-- WRAPPER TABLE -->
<table border="0" cellpadding="0" cellspacing="0" width="600" class="wrapper">
<tr>
<td>
<!-- TWO COLUMNS (ROW 1) -->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td>
<!-- LEFT COLUMN -->
<table border="0" cellpadding="0" cellspacing="0" width="47%" align="left" class="wrapper">
<tr>
<td>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td class="mobile-image-pad">
<a href="album/location" target="_blank">
<img src="img/url" alt="Kapanda" width="280" height="218" border="0" style="display: block; padding: 0; color: #ffffff; font-family: Arial, sans-serif; font-weight: bold; font-size: 18px; background-color: #589263; -webkit-border-radius: 4px; border-radius: 4px;" class="fluid-image" />
</a>
</td>
</tr>
<tr>
<td align="left" style="padding: 20px 0 0 0; color: #A50001; font-family: 'Libre Baskerville', serif; font-weight: bold; font-size: 18px; line-height: 22px; text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);" class="mobile-title-pad">
Title
</td>
</tr>
<tr>
<td align="left" style="padding: 10px 0 10px 0; color: #666666; font-family: 'Cabin', sans-serif; font-weight: normal; font-size: 18px; line-height: 22px;" class="mobile-text-pad">
description more description!
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- RIGHT COLUMN -->
<table border="0" cellpadding="0" cellspacing="0" width="47%" align="right" class="wrapper">
<tr>
<td class="mobile-column-right">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td class="mobile-image-pad">
<a href="album/location" target="_blank">
<img src="url/img" alt="Hawaii Sunset" width="280" height="218" border="0" style="display: block; padding: 0; color: #ffffff; font-family: Arial, sans-serif; font-weight: bold; font-size: 18px; background-color: #589263; -webkit-border-radius: 4px; border-radius: 4px;" class="fluid-image" />
</a>
</td>
</tr>
<tr>
<td align="left" style="padding: 20px 0 0 0; color: #339969; font-family: 'Libre Baskerville', serif; font-weight: bold; font-size: 18px; line-height: 22px; text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);" class="mobile-title-pad">
Title
</td>
</tr>
<tr>
<td align="left" style="padding: 10px 0 10px 0; color: #666666; font-family: 'Cabin', sans-serif; font-weight: normal; font-size: 18px; line-height: 22px;" class="mobile-text-pad">
Description More description.
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
Gmail generally doesn't support web-fonts. If you have a web font installed on your own computer, you’ll be able to see it in Gmail, but that's it.
Gmail supports #media queries almost everywhere, but not everywhere. The Litmus article you referenced contains a support table of Gmail products and their #media query support.
There's little telling which product MailChimp Or Litmus are using to generate their previews, so it could look fine on their end and break in your account... with no error on either end.
You said that you checked using Android app on mobile, and that seems like one of the Gmail products that doesn't support media queries ↓ ↓ ↓
This is pure conjecture, but from what I understand Google is done rolling out this change. So those red x's might remain unsupported for some time.
Gmail does support style blocks, but doesn't support selectors in CSS. Remove the selectors and your CSS will work. For example, change:
td[class="mobile-text-pad"]
to:
td.mobile-text-pad
And it should work.

Resources