Improvements to the templates

This commit is contained in:
YevhenBondarenko 2020-11-18 15:28:16 +02:00 committed by Andrew Shvayka
parent 3feb32c0f6
commit fc7b42c3d6
4 changed files with 314 additions and 210 deletions

View File

@ -297,15 +297,9 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
if (StringUtils.isNotEmpty(email)) { if (StringUtils.isNotEmpty(email)) {
result.forEach((apiFeature, stateValue) -> { result.forEach((apiFeature, stateValue) -> {
ApiUsageRecordKey[] keys = ApiUsageRecordKey.getKeys(apiFeature);
ApiUsageStateMailMessage[] msgs = new ApiUsageStateMailMessage[keys.length];
for (int i = 0; i < keys.length; i++) {
ApiUsageRecordKey key = keys[i];
msgs[i] = new ApiUsageStateMailMessage(key, state.getProfileThreshold(key), state.get(key));
}
mailExecutor.submit(() -> { mailExecutor.submit(() -> {
try { try {
mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, msgs[0]); mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, createStateMailMessage(state, apiFeature, stateValue));
} catch (ThingsboardException e) { } catch (ThingsboardException e) {
log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e); log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e);
} }
@ -316,6 +310,33 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
} }
} }
private ApiUsageStateMailMessage createStateMailMessage(TenantApiUsageState state, ApiFeature apiFeature, ApiUsageStateValue stateValue) {
StateChecker checker = getStateChecker(stateValue);
for (ApiUsageRecordKey apiUsageRecordKey : ApiUsageRecordKey.getKeys(apiFeature)) {
long threshold = state.getProfileThreshold(apiUsageRecordKey);
long warnThreshold = state.getProfileWarnThreshold(apiUsageRecordKey);
long value = state.get(apiUsageRecordKey);
if (checker.check(threshold, warnThreshold, value)) {
return new ApiUsageStateMailMessage(apiUsageRecordKey, threshold, value);
}
}
return null;
}
private StateChecker getStateChecker(ApiUsageStateValue stateValue) {
if (ApiUsageStateValue.ENABLED.equals(stateValue)) {
return (t, wt, v) -> true;
} else if (ApiUsageStateValue.WARNING.equals(stateValue)) {
return (t, wt, v) -> v < t && v >= wt;
} else {
return (t, wt, v) -> v >= t;
}
}
private interface StateChecker {
boolean check(long threshold, long warnThreshold, long value);
}
private void checkStartOfNextCycle() { private void checkStartOfNextCycle() {
updateLock.lock(); updateLock.lock();
try { try {

View File

@ -30,6 +30,7 @@ import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.ApiFeature; import org.thingsboard.server.common.data.ApiFeature;
import org.thingsboard.server.common.data.ApiUsageRecordKey;
import org.thingsboard.server.common.data.ApiUsageStateMailMessage; import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
import org.thingsboard.server.common.data.ApiUsageStateValue; import org.thingsboard.server.common.data.ApiUsageStateValue;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
@ -261,19 +262,36 @@ public class DefaultMailService implements MailService {
switch (stateValue) { switch (stateValue) {
case ENABLED: case ENABLED:
model.put("apiLabel", toEnabledValueLabel(apiFeature));
message = mergeTemplateIntoString("state.enabled.ftl", model); message = mergeTemplateIntoString("state.enabled.ftl", model);
break; break;
case WARNING: case WARNING:
model.put("apiLimitValueLabel", toDisabledValueLabel(msg.getKey(), msg.getThreshold()));
model.put("apiValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(msg.getKey(), msg.getValue()));
message = mergeTemplateIntoString("state.warning.ftl", model); message = mergeTemplateIntoString("state.warning.ftl", model);
break; break;
case DISABLED: case DISABLED:
model.put("apiLimitValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(msg)); model.put("apiLimitValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(msg.getKey(), msg.getThreshold()));
message = mergeTemplateIntoString("state.disabled.ftl", model); message = mergeTemplateIntoString("state.disabled.ftl", model);
break; break;
} }
sendMail(mailSender, mailFrom, email, subject, message); sendMail(mailSender, mailFrom, email, subject, message);
} }
private String toEnabledValueLabel(ApiFeature apiFeature) {
switch (apiFeature) {
case DB:
return "save";
case TRANSPORT:
return "receive";
case JS:
case RE:
return "invoke";
default:
throw new RuntimeException("Not implemented!");
}
}
private String toDisabledValueLabel(ApiFeature apiFeature) { private String toDisabledValueLabel(ApiFeature apiFeature) {
switch (apiFeature) { switch (apiFeature) {
case DB: case DB:
@ -288,17 +306,17 @@ public class DefaultMailService implements MailService {
} }
} }
private String toDisabledValueLabel(ApiUsageStateMailMessage msg) { private String toDisabledValueLabel(ApiUsageRecordKey key, long value) {
switch (msg.getKey()) { switch (key) {
case STORAGE_DP_COUNT: case STORAGE_DP_COUNT:
case TRANSPORT_DP_COUNT: case TRANSPORT_DP_COUNT:
return (msg.getThreshold() / 1000000) + "M data points"; return (value / 1000000) + "M data points";
case TRANSPORT_MSG_COUNT: case TRANSPORT_MSG_COUNT:
return (msg.getThreshold() / 1000000) + "M messages"; return (value / 1000000) + "M messages";
case JS_EXEC_COUNT: case JS_EXEC_COUNT:
return (msg.getThreshold() / 1000000) + "M JavaScript functions"; return (value / 1000000) + "M JavaScript functions";
case RE_EXEC_COUNT: case RE_EXEC_COUNT:
return (msg.getThreshold() / 1000000) + "M Rule Engine nodes"; return (value / 1000000) + "M Rule Engine nodes";
default: default:
throw new RuntimeException("Not implemented!"); throw new RuntimeException("Not implemented!");
} }

View File

@ -15,112 +15,141 @@
limitations under the License. limitations under the License.
--> -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
<head> <head>
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Thingsboard - Api Usage State</title> <title>Thingsboard - Api Usage State</title>
<style type="text/css"> <style type="text/css">
img { img {
max-width: 100%; max-width: 100%;
} }
body {
-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; body {
} -webkit-font-smoothing: antialiased;
body { -webkit-text-size-adjust: none;
background-color: #f6f6f6; width: 100% !important;
} height: 100%;
@media only screen and (max-width: 640px) { line-height: 1.6em;
body { }
padding: 0 !important;
} body {
h1 { background-color: #f6f6f6;
font-weight: 800 !important; margin: 20px 0 5px !important; }
}
h2 { @media only screen and (max-width: 640px) {
font-weight: 800 !important; margin: 20px 0 5px !important; body {
} padding: 0 !important;
h3 { }
font-weight: 800 !important; margin: 20px 0 5px !important;
} h1 {
h4 { font-weight: 800 !important;
font-weight: 800 !important; margin: 20px 0 5px !important; margin: 20px 0 5px !important;
} }
h1 {
font-size: 22px !important; h2 {
} font-weight: 800 !important;
h2 { margin: 20px 0 5px !important;
font-size: 18px !important; }
}
h3 { h3 {
font-size: 16px !important; font-weight: 800 !important;
} margin: 20px 0 5px !important;
.container { }
padding: 0 !important; width: 100% !important;
} h4 {
.content { font-weight: 800 !important;
padding: 0 !important; margin: 20px 0 5px !important;
} }
.content-wrap {
padding: 10px !important; h1 {
} font-size: 22px !important;
.invoice { }
width: 100% !important;
} h2 {
} font-size: 18px !important;
</style> }
h3 {
font-size: 16px !important;
}
.container {
padding: 0 !important;
width: 100% !important;
}
.content {
padding: 0 !important;
}
.content-wrap {
padding: 10px !important;
}
.invoice {
width: 100% !important;
}
}
</style>
</head> </head>
<body itemscope itemtype="http://schema.org/EmailMessage" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6"> <body itemscope itemtype="http://schema.org/EmailMessage"
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;"
bgcolor="#f6f6f6">
<table class="body-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td> <table class="main"
<td class="container" width="600" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; display: block !important; max-width: 600px !important; clear: both !important; margin: 0 auto;" valign="top"> style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; border-radius: 3px; width: 100%; background-color: #f6f6f6; margin: 0px auto;"
<div class="content" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; max-width: 600px; display: block; margin: 0 auto; padding: 20px;"> cellspacing="0" cellpadding="0" bgcolor="#f6f6f6">
<table class="main" width="100%" cellpadding="0" cellspacing="0" itemprop="action" itemscope itemtype="http://schema.org/ConfirmAction" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; border-radius: 3px; background-color: #fff; margin: 0; border: 1px solid #e9e9e9;" bgcolor="#fff"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td class="content-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 20px;" valign="top"> <tbody>
<meta itemprop="name" content="Confirm Email" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;" /><table width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> <tr style="box-sizing: border-box; margin: 0px;">
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> <td class="content-wrap" style="box-sizing: border-box; vertical-align: top; margin: 0px; padding: 20px;"
<td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> align="center" valign="top">
<h2>Thingsboard Api Usage State for tenant has been updated</h2> <table style="box-sizing: border-box; border: 1px solid #e9e9e9; border-radius: 3px; margin: 0px; height: 223px; padding: 20px; background-color: #ffffff; width: 600px; max-width: 600px !important;"
</td> width="600" cellspacing="0" cellpadding="0">
</tr> <tbody>
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0 ;"> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
<td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> <td class="content-block"
Thingsboard Usage state ${apiFeature} was updated to status ENABLED. style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 84px;"
</td> valign="top">
</tr> <h2>Your ThingsBoard account feature was enabled</h2>
<#list apiUsageStateMailMessages as msg> </td>
<tr> </tr>
<td> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
${msg.key.apiLimitKey} = ${msg.threshold} <td class="content-block"
</td> style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
</tr> valign="top">We have enabled the ${apiFeature} for your account and ThingsBoard already able to ${apiLabel} messages.
<tr> </td>
<td> </tr>
${msg.key.apiCountKey} = ${msg.value} <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
</td> <td class="content-block"
</tr> style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
</#list> valign="top">&mdash; The ThingsBoard
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> </td>
<td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> </tr>
&mdash; The Thingsboard </tbody>
</td> </table>
</tr></table></td>
</tr>
</table>
<div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;">
<table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
<td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td>
</tr>
</table>
</div>
</div>
</td> </td>
<td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td>
</tr> </tr>
</tbody>
</table>
<table style="color: #999999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; margin: 0px auto; height: 64px; background-color: #f6f6f6; width: 100%;"
cellpadding="0px 0px 20px">
<tbody>
<tr style="box-sizing: border-box; margin: 0px;">
<td class="aligncenter content-block"
style="box-sizing: border-box; font-size: 12px; margin: 0px; padding: 0px 0px 20px; width: 600px; text-align: center; vertical-align: middle;"
align="center" valign="top">This email was sent to&nbsp;<a
style="box-sizing: border-box; color: #999999; margin: 0px;"
href="mailto:${targetEmail}">${targetEmail}</a>&nbsp;by ThingsBoard.
</td>
</tr>
</tbody>
</table> </table>
</body> </body>
</html> </html>

View File

@ -15,112 +15,148 @@
limitations under the License. limitations under the License.
--> -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
<head> <head>
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Thingsboard - Api Usage State</title> <title>Thingsboard - Api Usage State</title>
<style type="text/css"> <style type="text/css">
img { img {
max-width: 100%; max-width: 100%;
} }
body {
-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; body {
} -webkit-font-smoothing: antialiased;
body { -webkit-text-size-adjust: none;
background-color: #f6f6f6; width: 100% !important;
} height: 100%;
@media only screen and (max-width: 640px) { line-height: 1.6em;
body { }
padding: 0 !important;
} body {
h1 { background-color: #f6f6f6;
font-weight: 800 !important; margin: 20px 0 5px !important; }
}
h2 { @media only screen and (max-width: 640px) {
font-weight: 800 !important; margin: 20px 0 5px !important; body {
} padding: 0 !important;
h3 { }
font-weight: 800 !important; margin: 20px 0 5px !important;
} h1 {
h4 { font-weight: 800 !important;
font-weight: 800 !important; margin: 20px 0 5px !important; margin: 20px 0 5px !important;
} }
h1 {
font-size: 22px !important; h2 {
} font-weight: 800 !important;
h2 { margin: 20px 0 5px !important;
font-size: 18px !important; }
}
h3 { h3 {
font-size: 16px !important; font-weight: 800 !important;
} margin: 20px 0 5px !important;
.container { }
padding: 0 !important; width: 100% !important;
} h4 {
.content { font-weight: 800 !important;
padding: 0 !important; margin: 20px 0 5px !important;
} }
.content-wrap {
padding: 10px !important; h1 {
} font-size: 22px !important;
.invoice { }
width: 100% !important;
} h2 {
} font-size: 18px !important;
</style> }
h3 {
font-size: 16px !important;
}
.container {
padding: 0 !important;
width: 100% !important;
}
.content {
padding: 0 !important;
}
.content-wrap {
padding: 10px !important;
}
.invoice {
width: 100% !important;
}
}
</style>
</head> </head>
<body itemscope itemtype="http://schema.org/EmailMessage" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6"> <body itemscope itemtype="http://schema.org/EmailMessage"
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;"
bgcolor="#f6f6f6">
<table class="body-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; background-color: #f6f6f6; margin: 0;" bgcolor="#f6f6f6"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td> <table class="main"
<td class="container" width="600" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; display: block !important; max-width: 600px !important; clear: both !important; margin: 0 auto;" valign="top"> style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; border-radius: 3px; width: 100%; background-color: #f6f6f6; margin: 0px auto;"
<div class="content" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; max-width: 600px; display: block; margin: 0 auto; padding: 20px;"> cellspacing="0" cellpadding="0" bgcolor="#f6f6f6">
<table class="main" width="100%" cellpadding="0" cellspacing="0" itemprop="action" itemscope itemtype="http://schema.org/ConfirmAction" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; border-radius: 3px; background-color: #fff; margin: 0; border: 1px solid #e9e9e9;" bgcolor="#fff"><tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"><td class="content-wrap" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 20px;" valign="top"> <tbody>
<meta itemprop="name" content="Confirm Email" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;" /><table width="100%" cellpadding="0" cellspacing="0" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> <tr style="box-sizing: border-box; margin: 0px;">
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> <td class="content-wrap" style="box-sizing: border-box; vertical-align: top; margin: 0px; padding: 20px;"
<td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> align="center" valign="top">
<h2>Thingsboard Api Usage State for tenant has been updated</h2> <table style="box-sizing: border-box; border: 1px solid #e9e9e9; border-radius: 3px; margin: 0px; height: 223px; padding: 20px; background-color: #ffffff; width: 600px; max-width: 600px !important;"
</td> width="600" cellspacing="0" cellpadding="0">
</tr> <tbody>
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
<td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> <td class="content-block"
Thingsboard Usage state ${apiFeature} was updated to status WARNING. style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 84px;"
</td> valign="top">
</tr> <h2>Your ThingsBoard account feature may be disabled</h2>
<#list apiUsageStateMailMessages as msg> </td>
<tr> </tr>
<td> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
${msg.key.apiLimitKey} = ${msg.threshold} <td class="content-block"
</td> style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
</tr> valign="top">
<tr> Your ${apiFeature} limit (${apiLimitValueLabel}) is almost exhausted. <br>ThingsBoard has already&nbsp;${apiValueLabel}.<br> ${apiFeature} will be disabled for your account when limit will be reached.
<td> </td>
${msg.key.apiCountKey} = ${msg.value} </tr>
</td> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
</tr> <td class="content-block"
</#list> style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 59px;"
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> valign="top">Please contact your system administrator to resolve the issue.
<td class="content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0; padding: 0 0 20px;" valign="top"> </td>
&mdash; The Thingsboard </tr>
</td> <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
</tr></table></td> <td class="content-block"
</tr> style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
</table> valign="top">&mdash; The ThingsBoard
<div class="footer" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; width: 100%; clear: both; color: #999; margin: 0; padding: 20px;"> </td>
<table width="100%" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> </tr>
<tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;"> </tbody>
<td class="aligncenter content-block" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; vertical-align: top; color: #999; text-align: center; margin: 0; padding: 0 0 20px;" align="center" valign="top">This email was sent to <a href="mailto:${targetEmail}" style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 12px; color: #999; text-decoration: underline; margin: 0;">${targetEmail}</a> by Thingsboard.</td> </table>
</tr>
</table>
</div>
</div>
</td> </td>
<td style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0;" valign="top"></td>
</tr> </tr>
</tbody>
</table>
<table style="color: #999999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; margin: 0px auto; height: 64px; background-color: #f6f6f6; width: 100%;"
cellpadding="0px 0px 20px">
<tbody>
<tr style="box-sizing: border-box; margin: 0px;">
<td class="aligncenter content-block"
style="box-sizing: border-box; font-size: 12px; margin: 0px; padding: 0px 0px 20px; width: 600px; text-align: center; vertical-align: middle;"
align="center" valign="top">This email was sent to&nbsp;<a
style="box-sizing: border-box; color: #999999; margin: 0px;"
href="mailto:${targetEmail}">${targetEmail}</a>&nbsp;by ThingsBoard.
</td>
</tr>
</tbody>
</table> </table>
</body> </body>
</html> </html>