هذا المنشور موجه للمطور الذي يريد الحصول على أقصى استفادة من قدرات قالب البريد الإلكتروني لـ SparkPost. يُفترض أنك مرتاح لقراءة محتوى JSON واتباع تدفق البرمجة الأساسية. عند تقديم مصطلحات جديدة لك مثل RFC 5322، يتم ربط النص بمرجعه المصدر. مع خروج ذلك من الطريق، دعونا نبدأ مباشرة في الموضوع.
تجعل قدرات القوالب والإرسال الخاصة بـ SparkPost إرسال رسائل البريد الإلكتروني أمرًا سهلاً. توفر هذه القدرات تجريداً للمحتوى النصي وHTML مما يعني أنه في معظم الأحيان لا يوجد حاجة لترميز تنسيق البريد الإلكتروني الخام مباشرةً والذي يُعرَّف في RFC 5322 المعروف سابقًا باسم (RFC 822). ولكن في بعض الأحيان قد ترغب في إنشاء رسائل أكثر تعقيدًا تحتوي على أجزاء من ملحقات بريد الإنترنت المتعددة الأغراض (MIME) التي لا يتم توضيحها مباشرة عبر واجهة SparkPost المبنية على REST.
تبسيط تكوين البريد الإلكتروني
أولاً، دعونا نستعرض سيناريو مشمس لإرسال بريد إلكتروني. استخدم نقطة النهاية للإرسال لتزويد النص
والمحتوى HTML. خلف الكواليس، يتولى SparkPost توليفة بريد إلكتروني صالح وفقًا لـ RFC 5322. سيقوم SparkPost بإدخال متغيرات الاستبدال من substitution_data في النص والمحتوى HTML. هذه طريقة قوية لتوليد محتوى مخصص لكل مستلم في قالب مشترك.
إليك مثال لعملية إرسال مع محتوى HTML ونص مع substitution_data.
{
"options": {
"open_tracking": true,
"click_tracking": true
},
"campaign_id": "christmas_campaign",
"return_path": "bounces-christmas-campaign@domain.com",
"metadata": {
"user_type": "students"
},
"substitution_data": {
"sender": "Big Store Team"
},
"recipients": [
{
"return_path": "123@bounces.domain.com",
"address": {
"email": "wilma@domain.com",
"name": "Wilma Flintstone"
},
"tags": [
"greeting",
"prehistoric",
"fred",
"flintstone"
],
"metadata": {
"place": "Bedrock"
},
"substitution_data": {
"customer_type": "Platinum"
}
}
],
"content": {
"from": {
"name": "Fred Flintstone",
"email": "fred@domain.com"
},
"subject": "Big Christmas savings!",
"reply_to": "Christmas Sales <sales@domain.com>",
"headers": {
"X-Customer-Campaign-ID": "christmas_campaign"
},
"text": "Hi {{address.name}} \nSave big this Christmas in your area {{place}}! \nClick http://www.mysite.com and get huge discount\n Hurry, this offer is only to {{user_type}}\n {{sender}}",
"html": "<p>Hi {{address.name}} <br>Save big this Christmas in your area {{place}}! <br>Click <a href=\"http://www.mysite.com\">here</a> and get huge discount</p><p>Hurry, this offer is only to {{user_type}}</p><p>{{sender}}</p>"
}
}
استبدال مصفوفات البيانات
يدرك العديد من الأشخاص أن نقاط النهاية للإرسال والقوالب الخاصة بـ SparkPost يمكنها تنفيذ استبدالات بسيطة في رؤوس البريد الإلكتروني وأجسام البريد الإلكتروني. ولكن العديد يغفلون قدرة تقديم المحتوى الشرطي أو مصفوفات البيانات التي يمكن استبدالها كذلك. يمكنك أيضًا تقديم محتوى فريد لكل مستلم. في هذا المثال نرسل مصفوفة من الروابط الفريدة لكل مستلم.
يتم تحقيق ذلك بتقديم مصفوفة JSON من البيانات التي سيتم ملؤها في جسم البريد الإلكتروني. بمجرد توفير البيانات، سيستخدم SparkPost منطقًا في القالب لملئها.
في هذا المثال، سيبحث SparkPost عن بيانات استبدال تسمى “files_html” ويفعل “for each” على كل عنصر في المصفوفة. سيُنشئ صفًا مع قيمة “file” في عنصر “files_html”. لاحظ الأقواس المتعددة حول “loop_var.file“. هذا لأن كل عنصر من عناصر المصفوفة يحتوي على HTML ونحتاج إلى إخبار الخادم باستخدامه كما هو وعدم معالجته. سيكون الجزء الخاص بالنص عبارة عن ملصق نصي بسيط وعنوان URL للملف.
<table>
{{each files_html}}
<tr>
<td>{{{loop_var.file}}}</td>
</tr>
{{ end }}
</table>
إليك المثال المكتمل العامل:
{
"recipients": [
{
"address": {
"email": "recipient1@domain.com"
},
"substitution_data": {
"files_html": [
{
"file": "<a href=\"http://domain.com/file1a.txt\">File 1a Description</a>"
},
{
"file": "<a href=\"http://domain.com/file2a.txt\">File 2a Description</a>"
}
],
"files_plain": [
{
"file": "File 1a -- http://domain.com/file1a.txt"
},
{
"file": "File 2a -- http://domain.com/file2a.txt"
}
]
}
},
{
"address": {
"email": "recipient2@domain.com"
},
"substitution_data": {
"files_html": [
{
"file": "<a href=\"http://domain.com/file1b.txt\">File 1b Description</a>"
},
{
"file": "<a href=\"http://domain.com/file2b.txt\">File 2b Description</a>"
}
],
"files_plain": [
{
"file": "File 1b -- http://domain.com/file1b.txt"
},
{
"file": "File 2b -- http://domain.com/file2b.txt"
}
]
}
}
],
"return_path": "chris@test.domain.com",
"content": {
"from": {
"name": "chris@test.domain.com",
"email": "chris@test.domain.com"
},
"subject": "Sending with SparkPost is Fun",
"html": "<b>Your Files:</b><br>\n<table>\n {{each files_html}}\n <tr><td>{{{loop_var.file}}}</td></tr>\n {{ end }}\n</table>\n",
"text": "Your Files:\n{{each files_plain}} {{loop_var.file}}\n{{ end }}\n"
}
}
نصيحة احترافية: في كودك، يُنصح بفصل التعليمات البرمجية للعرض عن البيانات، لكن الهدف هنا كان جعل المثال بسيطًا وسهل المتابعة قدر الإمكان لذا أنشأنا مصفوفتين. مصفوفة واحدة لجزء HTML والأخرى للجزء النصي. في الاستخدام الإنتاجي، سيكون من الشائع وجود مجموعة واحدة من البيانات وكتابة المنطق في كود القالب.
المرفقات في قدرات الإرسال
تقدم نقطة النهاية للإرسال أيضًا تجريدًا لإرسال المرفقات. أدناه سترى أن المرفقات يتم تحديدها في مصفوفة المرفقات المحتوى حيث يصف كل كائن في المصفوفة عنصر مرفق فردي. كما هو الحال من قبل، سيتولى SparkPost تشفير النص، HTML، الاستبدالات وتكرار المصفوفة المرفقة لترميز رسالة بريد إلكتروني مشكّلة بشكل صحيح.
تملي أفضل الممارسات أن تجنب إرسال المرفقات يكون الأفضل ما لم يكن مطلوبًا صراحة كجزء من خدمتك.
أدناه الحقول المطلوبة للمرفق:
النوع: نوع MIME للمرفق
الاسم: اسم ملف المرفق
البيانات: بيانات الملف المشفرة بقاعدة 64
هذا هو شكل المرفق داخل جزء محتوى الإرسال:
"content": {
"attachments": [
{
"type": "audio/mp3",
"name": "voicemail.mp3",
"data": "TVAzIERhdGEK"
}
]
}
يمكنك أيضًا إرسال “الصور المضمّنة” في الإرسال. تشبه هذه العمليات المرفقات للغاية وتُحدّد في مصفوفة content.inline_images حيث تكون كل كائنات inline_image مشابهة للكائن المرفق الموضح أعلاه.
المرفقات في القوالب
الآن وقد حصلنا على الخلفية المناسبة لإرسال المرفقات باستخدام نقطة النهاية للإرسال دعونا نلقي نظرة على كيفية القيام بذلك باستخدام القوالب. في وقت كتابة هذا النص، لا يوجد تجريد للمرفقات كما تجدها للنقل المضمّن. قد تستنتج أن القوالب لا يمكن إنشاؤها مع المرفقات. ستكون صحيحًا جزئيًا ولكن هناك حلاً بديلاً، على الرغم من أنك لن تكون معزولًا بعد الآن عن تنسيق RFC 5322.
يمكنك تحقيق المرفقات في القوالب عن طريق ترميز محتوى RFC 5322 بنفسك والذي يتضمن المرفقات. الخبر الجيد هو أنك لن تفقد القدرة على استخدام بيانات الاستبدال في رؤوس البريد الإلكتروني، وHTML وأجزاء النص. كن على علم أن هذا النوع من القوالب يحد من الاستبدالات للرؤوس وأول HTML وأول جزء نصي.
إليك مثال عن كيفية القيام بذلك.
رسالة البريد الإلكتروني RFC822
قم بإنشاء بريدك الإلكتروني RFC 5322 مع بيانات الاستبدال المرغوب فيها. لقد أنشأت هذا في عميل البريد الخاص بي وأرسلته إلى نفسي. بمجرد أن استلمته، نسخت المصدر واستبدلت الحقول التي أريد استبدالها ديناميكيًا.
MIME-Version: 1.0
Reply-To: {{replyto}}
Subject: {{subject}}
From: {{from}}
To: {{address.email}}
Content-Type: multipart/mixed; boundary="001a113c48b0b89d92052d3051da"
--001a113c48b0b89d92052d3051da
Content-Type: multipart/alternative; boundary="001a113c48b0b89d89052d3051d8"
--001a113c48b0b89d89052d3051d8
Content-Type: text/plain; charset=UTF-8
Email with a *text attachment*.
{{body2}}
--001a113c48b0b89d89052d3051d8
Content-Type: text/html; charset=UTF-8
<div dir="ltr">
<div>Email with a <i>text attachment</i>.</div>
{{body1}}
<
الجزء الأحدث MIME في هذه الرسالة سترى Content-Disposition: attachment; filename=myfile.txt”. هذا هو المكان الذي يُعَرَّف فيه اسم الملف. من المؤكد أن محتوى مرفقاتك سيكون أكثر تعقيدًا بكثير ولكن هذا المثال يحاول إبقاءه بسيطًا.
قالب مخزن
بمجرد الحصول على بريد إلكتروني مؤلف وفقًا لـ RFC 5322 صالح، خزنه باستخدام صيغة email_rfc822 لنقطة نهاية القوالب بدلاً من استخدام حقول النص وHTML. هذه أمثلة على كيفية محتوى الرسالة:
{
"content": {
"email_rfc822": "MIME-Version: 1.0\nReply-To: {{replyto}}\nSubject: {{subject}}\nFrom: {{from}}\nTo: {{address.email}}\nContent-Type: multipart/mixed; boundary=001a113c48b0b89d92052d3051da\n\n--001a113c48b0b89d92052d3051da\nContent-Type: multipart/alternative; boundary=001a113c48b0b89d89052d3051d8\n\n--001a113c48b0b89d89052d3051d8\nContent-Type: text/plain; charset=UTF-8\n\nEmail with a *text attachment*.\n\n{{body2}}\n\n--001a113c48b0b89d89052d3051d8\nContent-Type: text/html; charset=UTF-8\n\n<div dir=\"ltr\"><div>Email with a <i>text attachment</i>.</div>\n\n{{body1}}\n</div>\n\n--001a113c48b0b89d89052d3051d8--\n--001a113c48b0b89d92052d3051da\nContent-Type: text/plain; charset=US-ASCII; name=\"myfile.txt\"\nContent-Disposition: attachment; filename=\"myfile.txt\"\nContent-Transfer-Encoding: base64\nX-Attachment-Id: f_ild455ce0\n\nVGhpcyBpcyBteSBzaW1wbGUgdGV4dCBmaWxlLgo=\n--001a113c48b0b89d92052d3051da--"
},
"name": "_TMP_TEMPLATE_TEST"
}
عندما تكتمل الطلب، سيرد SparkPost بمعرف فريد للقالب الجديد الخاص بك. على سبيل المثال xxxxxxx.
إرسال القالب
الخبر الجيد هو أن إنشاء محتوى RFC 5322 كان الجزء الصعب. من هنا فصاعدًا، يعد إرسال ذلك القالب مع SparkPost هو بالظبط مثل إرسال أي قالبي آخر.
إليك كيفية إرسال ذلك القالب وملء بيانات الاستبدال:
{
"campaign_id": "MyCampaign",
"return_path": "myReturnPath@yourdomain.com",
"substitution_data": {
"replyto": "myReplyToh@yourdomain.com",
"from": "MyFrom@yourdomain.com",
"subject": "my subject",
"body1": "Extra content for the HTML part",
"body2": "Extra content for the text part"
},
"recipients": [
{
"substitution_data": {},
"address": {
"email": "test1@domain.com",
"name": "test1"
}
}
],
"content": {
"template_id": "xxxxxxx",
"use_draft_template": true
}
}
القوالب من واجهة برمجة تطبيقات عميل البريد
إذا كنت تستخدم لغة برمجة تحتوي على مكتبة لإنشاء بريد إلكتروني، يمكنك استخدام ذلك لإنشاء القالب برمجيًا أو حتى إرسال الرسالة مدمجة. إليك مثال عن استخدام JavaMail من خلال نقطة نهاية الإرسال لـ SparkPost. يجب أن تكون هذه الطريقة قابلة للترجمة بسهولة إلى PHP أو لغتك المفضلة.
public class App extends SparkPostBaseApp {
public static void main(String[] args) throws Exception {
Logger.getRootLogger().setLevel(Level.DEBUG);
App app = new App();
app.runApp();
}
private void runApp() throws Exception {
Message message = createMultipartMessage();
String rfc822Content = getMessageAsString(message);
rfc822Content = "To: {{address.email}}\r\nFrom: {{from}}\r\n" + rfc822Content;
String fromAddress = getFromAddress();
String[] recipients = getTestRecipients();
sendEmail(fromAddress, recipients, rfc822Content);
}
private void sendEmail(String from, String[] recipients, String email)
throws SparkPostException, IOException {
Client sparkpostClient = newConfiguredClient();
TransmissionWithRecipientArray transmission = new TransmissionWithRecipientArray();
List<RecipientAttributes> recipientArray = new ArrayList<>();
for (String recipient : recipients) {
RecipientAttributes recipientAttribs = new RecipientAttributes();
recipientAttribs.setAddress(new AddressAttributes(recipient));
recipientArray.add(recipientAttribs);
}
transmission.setRecipientArray(recipientArray);
transmission.setReturnPath(from);
Map<String, String> substitutionData = new HashMap<>();
substitutionData.put("from", from);
substitutionData.put("name", "Your Name Here");
transmission.setSubstitutionData(substitutionData);
TemplateContentAttributes contentAttributes = new TemplateContentAttributes();
contentAttributes.setEmailRFC822(email);
transmission.setContentAttributes(contentAttributes);
RestConnection connection = new RestConnection(sparkpostClient, getEndPoint());
Response response = ResourceTransmissions.create(connection, 0, transmission);
if (response.getResponseCode() == 200) {
System.out.println("✅ Transmission Response: " + response);
} else {
System.err.println("❌ TRANSMISSION ERROR: " + response);
}
}
private Message createMultipartMessage() throws MessagingException {
Properties props = new Properties();
props.put("mail.smtp.host", "none");
Session session = Session.getDefaultInstance(props, null);
Message message = new MimeMessage(session);
message.setSubject("A multipart MIME message demo");
Multipart multiPart = new MimeMultipart("mixed");
MimeMultipart altPart = new MimeMultipart("alternative");
MimeBodyPart textPart = new MimeBodyPart();
textPart.setText("{{name}},\r\nplain text content", "utf-8");
MimeBodyPart htmlPart = new MimeBodyPart();
htmlPart.setContent("<b>{{name}},<br><br>Our HTML content</b>", "text/html; charset=utf-8");
altPart.addBodyPart(textPart);
altPart.addBodyPart(htmlPart);
MimeBodyPart altBodyPart = new MimeBodyPart();
altBodyPart.setContent(altPart);
multiPart.addBodyPart(altBodyPart);
MimeBodyPart attachmentPart = new MimeBodyPart();
String filename = "java_SparkPost_background.pdf";
DataSource source = new FileDataSource(filename);
attachmentPart.setDataHandler(new DataHandler(source));
attachmentPart.setFileName(filename);
multiPart.addBodyPart(attachmentPart);
message.setContent(multiPart);
return message;
}
private String getMessageAsString(Message msg) throws IOException, MessagingException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
msg.writeTo(out);
return out.toString("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 not found! " + e.getMessage());
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
الخاتمة
الآن بعد أن رأيت كيف يمكن استخدام SparkPost لإرسال بريد إلكتروني تقريباً معقد، قد ترغب في إلقاء نظرة على “SparkPost تدعم إرسال البريد الإلكتروني على Apple Watch” أو إلقاء نظرة على صيغة الاستبدال لرؤية كيفية استخدامها مع “if then else”، “التعبيرات الشرطية” أو “التكرار داخل مصفوفة” مباشرةً داخل القالب الخاص بك أو محتوى الإرسال.