هذا المنشور موجه للمطور الذي يريد الاستفادة القصوى من إمكانيات قالب البريد الإلكتروني لـ SparkPost. يُفترض أنك متعود على قراءة محتوى JSON واتباع تدفق البرمجة الأساسي. يتم تقديم المصطلحات الجديدة مثل RFC 5322، والنص مرتبط بمصدره المرجعي. مع إزاحة هذا جانبا، دعونا نبدأ مباشرة.
تجعل إمكانيات القالب والإرسال في SparkPost إرسال البريد الإلكتروني سهلاً. هذه الإمكانيات توفر تجريدًا لمحتوى النص وHTML مما يعني في معظم الأوقات أنه لا توجد حاجة إلى ترميز صيغة البريد الإلكتروني الخام مباشرة والتي تم تعريفها في RFC 5322 والمعروف سابقًا بـ(RFC 822). ولكن أحيانًا قد ترغب في إنشاء رسائل أكثر تعقيدًا تحتوي على أجزاء MIME (امتدادات متعددة الأغراض لبريد الإنترنت) أخرى غير مكشوفة مباشرة عبر واجهة برمجة التطبيقات RESTful لـ SparkPost.
تكوين البريد الإلكتروني المبسط
أولاً، دعونا نراجع سيناريو يوم مشمس لإرسال بريد إلكتروني. استخدم نقطة نهاية الإرسال لتوفير محتوى النص
و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 والأخرى للجزء النصي. في الاستخدام الإنتاجي، سيكون من الشائع أن يكون لديك مجموعة واحدة من البيانات وكتابة المنطق في كود القالب.
المرفقات في إمكانيات الإرسال
توفر نقطة نهاية الإرسال أيضًا تجريداً لإرسال المرفقات. فيما يلي سترى أن المرفقات محددة في content.attachments مصفوفة حيث يصف كل كائن في المصفوفة عنصر مرفق فردي. كما كان من قبل، سيتكلف SparkPost بترميز النص, HTML, الاستبدالات وتكرار المصفوفة المرفقة لترميز رسالة بريد إلكتروني مشكلة بشكل صحيح.
تملي أفضل الممارسات أن تجنب إرسال المرفقات هو الأمثل ما لم يكن مطلوبًا بشكل صريح كجزء من خدمتك.
فيما يلي الحقول المطلوبة لمرفق:
type: نوع MIME الخاص بالمرفق
name: اسم ملف المرفق
data: بيانات الملف المشفرة بأسلوب Base64
هذا ما يبدو عليه المرفق داخل فاصل محتوى الإرسال:
"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 في هذه الرسالة سترى 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”، “التعبيرات في الشرطيات” أو “التكرار عبر المصفوفات” مباشرة في قالبك أو محتوى الإرسال الخاص بك.