# E-posta Şablonu Yazma

https://dev.wisecp.com/tr/e-posta-sablonu-yazma

Platforma yeni bir e-posta eklemek üç küçük dosya yazmak ve onları hiçbiri atlanamayan dört ayrı yerde kaydetmektir.

## Genel Bakış

Bir e-posta için yazdığınız şey bir **parça** ve bir konu satırıdır. Çevresindeki belge, logo, footer, iletişim bloğu ve renkler paylaşılan kabuktan gelir. Kendi belge etiketini açan bir şablon çerçeveyle kavga eder.

İşin geri kalanı kayıttır. Yapılandırma kaydı olmadan olayın anahtarı yoktur ve devre dışı bildirilir. Çözümleyici kaydı olmadan gövdenin yazdığı değişkenler var olmaz, etiket olmadan panel ham anahtarı listeler.

## Ön Koşullar

- **çözümleyicisi olan bir grup**: Olayı mümkün olan her durumda mevcut bir gruba koyun. Yeni bir grup hem çözümleyici hem de çözümleyici haritasında bir kayıt ister; çözümleyicisi olmayan grup her dispatch'e hata döner.
- **motor ayarı**: Şablonlar yapılandırılmış motora göre yazılır ve gelen ağaç Smarty'dir. Başka bir yerden yer tutucu söz dizimi kopyalamadan önce `options/notification-template-engine` anahtarını kontrol edin.
- **kurulu her dil**: Diller arasında geri düşme yoktur. Üçlüyü kurulumun sahip olduğu her dilde paketleyin; yoksa eksik dilde okuyan alıcılar hiçbir şey almaz.
- **gideni okuyabilecek bir yol**: Kum havuzu mail modülü, bağlantı açmak yerine giden her mesajı diske yazar. Gövdeyi incelemenin en hızlı yolu budur; gerçek adres taşıyan bir kurulumda da tek güvenli yoldur.

## Yapı

### Parça Sözleşmesi

Kabuğun header'ı dış tabloyu açar ve açık bırakır; footer kapatır. Sizin gövdeniz ikisinin arasına oturur ve bu, gövdenin neyle başlayıp neyle bitebileceğini belirler.

```bash
{lang}/header.html   sayfa tablosunu açar, logoyu ve site başlığını basar, AÇIK bırakır
      ↓
{lang}/content.html  tek bir {$notifi_body} yer tutucusu
      ↓
   SİZİN DOSYANIZ     bir ya da birkaç tablo satırı: açık tabloyu sürdürür
      ↓
{lang}/footer.html   iletişim bloğu, bağlantılar, şirket bilgileri, sonra her şeyi KAPATIR
```

- **sayfa değil satır**: Bir tablo satırıyla başlayın, biriyle bitirin. Belge etiketi yok, head yok, body etiketi yok, stil sayfası yok: çerçeve hepsini zaten açtı.
- **sunum satır içine gider**: E-posta istemcileri stil sayfalarını atar, bu yüzden gelen her gövde biçimlendirmesini her elemanın üzerinde bir öznitelik olarak taşır. Yerleşimde tablo kullanılmasının sebebi de aynıdır.
- **renkler kurulumdan gelir**: Üçü enjekte edilir: `theme_color1`, `theme_color2` ve `theme_text_color`. Her biri baştaki işaretçi **olmadan** yalnız rakamları taşır; yani şablon işaretçiyi kendisi yazar, değeri ardına koyar: `bgcolor="#{$theme_color1}"`. Marka rengini asla sabit yazmayın.
- **mantık yorumda saklanabilir**: Gelen şablonlar döngüleri ve koşulları HTML yorumlarına sarar, böylece görsel bir düzenleyici onları bozmaz. Motor yine de çalıştırır; çıktıya yalnız yorum işaretleri kalır.

### Üç Dosya

| Dosya | Hangi kanalda okunur | İçerik |
| --- | --- | --- |
| `{name}.html` | e-posta | Gövde parçası. Gönderilmeden önce kabuğa sarılır. |
| `{name}.json` | e-posta | `{"subject": "..."}`. Aynı değişkenlerle üretilir, yani yer tutucu taşıyabilir. |
| `{name}.txt` | kısa mesaj | Kabuksuz gönderilen metin gövdesi. Olay kısa mesaj kanalını hiç kullanmasa bile gereklidir, çünkü panelin düzenlediği şey bu dosyadır. |

## Adım Adım

### 1. Üçlüyü Yazın

1. Grubu ve küçük harfli, tire ile ayrılmış bir olay adı seçin. Bu ikili, olayın diğer her yerdeki kimliğidir.
2. Kurulu her dil dizini altında `{name}.html`, `{name}.json` ve `{name}.txt` oluşturun.
3. Tablo işaretlemesini sıfırdan yazmak yerine en yakın gelen gövdeyi kopyalayın; boşluk ritmi ve renk değişkenleri orada zaten doğrudur.
4. Yer tutucuları motorun söz diziminde tutun. Başka bir motorun söz dizimiyle yazılmış yer tutucu göreceğiniz bir hata değildir. Dosyanın tamamını işlenmemiş bırakan bir derleme hatasıdır.

### 2. Olayı Kaydedin

1. `coremio/configuration/notifications.php` içinde grubun altına bir kayıt ekleyin. Anahtarlar aşağıdaki referansta.
2. `status` değerini 1 yapın ve olayın gerçekten kullandığı kanalları açın. 0'da bırakılan her şey sessiz kalır.
3. Yeniden yükleyin ve olayın artık panelin şablon listesinde göründüğünü doğrulayın. Görünmüyorsa kayıt yanlış grup anahtarının altındadır.

### 3. Değişkenleri Besleyin

1. `coremio/helpers/notification.php` içinde grubun çözümleyicisini açın ve olay adı için bir kayıt ekleyin.
2. Yalnızca grubun temel kümesinin vermediğini set edin. Fatura, hizmet, sipariş, alan adı ve talep çözümleyicilerinin her biri switch koşmadan önce tam bir küme kurar.
3. E-posta hesabın kendi adresine değil başka bir adrese gitmeliyse alıcıyı kayıt içinde ezin. Bunu çağrı noktasında değil orada yapmak, mevcut her çağıranın eskisi gibi davranmasını sağlar.
4. Dispatch'i çağırın ve dönen `status` değerini okuyun. Buradaki `error`, çözümleyicinin boş döndüğü, genellikle de varlığın yüklenemediği anlamına gelir.

### 4. Ne Zaman Gideceğine Karar Verin

1. Varsayılanda mesaj kuyruğa yazılır ve bir dakika içinde çıkar.
2. Müşterinin *beklediği* bir olay (kod, bağlantı, davet) bunun yerine yerinde teslim edilir. Adını `$sync_notifications` listesine, çözümleyiciyle aynı dosyaya ekleyin.
3. Tek bir çağrı bu listeyi değiştirmeden ezebilir: bağlama `'_sync' => true` geçin. Her zaman acil olan olay için listeyi, yalnız bir çağıran için acil olanda bağlam anahtarını kullanın.
4. Yerinde teslim istek içinde olur, dolayısıyla istek içinde de başarısız olur. Bir olayı oraya yalnızca gecikme riskten daha kötüyse koyun.

### 5. Önizlenebilir ve Adlandırılmış Yapın

1. Olay anahtarı için yönetici bildirim dil dosyalarına, her dilde, insan-okunur bir etiket ekleyin. Yoksa panel listesinde ham anahtarı gösterir.
2. Olayın kendi değişkenleri için `coremio/operations/AdminNotifications.php` içindeki önizleme operation'ına örnek değerler ekleyin. Önizleme çözümleyiciyi çalıştırmaz, yani ona verilmeyen her şey boş dize olarak çıkar.
3. Önizlemeyi açın. Derleme hatasının loglanmak yerine gösterildiği tek yer de burasıdır.

### 6. Doğrulayın

1. Önizlemeyi değil gerçek akışı tetikleyin.
2. Teslim edilen mesajı kum havuzu mail modülünün çıktı dizininden okuyun ve metne hiçbir yer tutucunun sızmadığını kontrol edin.
3. Aynısını diğer dildeki bir hesapla tekrarlayın. Bu adım, üçlüyü tek bir dil dizininde oluşturmuş olmanızı yakalar.

## Referans

### Yapılandırma Kaydı

Grubunun altında olay başına tek bir dizi. Bir şeyin gönderilip gönderilmeyeceğine yalnız `status` ve dört kanal anahtarı karar verir; geri kalanı kimin alacağını ve panelin ne göstereceğini şekillendirir.

```php
return [
    'notifications' => [
        'invoice' => [
            'invoice-created' => [
                'variables'   => '{invoice_idn},{invoice_total},{invoice_payment_link},{items}',
                'emails'      => '',
                'phones'      => null,
                'departments' => ['4'],
                'status'      => 1,
                'user-mail'   => 1,
                'admin-mail'  => 0,
                'user-sms'    => 1,
                'admin-sms'   => 0,
            ],
        ],
    ],
];
```

- **status**: Ana anahtar. 0 olması ya da kaydın hiç olmaması, şablona hiç dokunmadan her dispatch'in `disabled` yanıtı vermesine yol açar.
- **user-mail · user-sms**: Hesap sahibine o kanaldan yazılıp yazılmayacağı. Kısa mesaj ayrıca hesapta bir cep numarası ister; yoksa alıcı listeden düşer.
- **admin-mail · admin-sms**: Personele de yazılıp yazılmayacağı. Alıcılar aşağıdaki departmanlardan ve onları izleyen iki alandaki adreslerden çözülür; anahtar açıkken hiçbiri çözülmezse kök yöneticiye düşülür.
- **emails · phones**: Departmanların üstüne eklenen, virgülle ayrılmış ek personel alıcıları. Yalnız eşleşen yönetici anahtarı açıkken okunur.
- **departments**: Personeli kopyayı alacak destek departmanı kimlikleri. Kimlik dizelerinden oluşan bir dizi ve bir olayı herkese değil doğru ekibe yönlendirmenin olağan yolu.
- **user-notification**: Alıcının panel içi satır alıp almayacağı. Anahtarın yokluğu açık demektir; yeni bir anahtar tanıtıldığında mevcut olayların zilini korumasının sebebi budur.
- **admin-notification**: Personelin panel içi kopya alıp almayacağı. Anahtar yokken yanıt türetilir: personelin aksiyon almak zorunda olduğu kısa bir olay listesi için açık, aksi halde `admin-mail` değerini izler.
- **send-pdf**: Yalnız fatura grubu. Yokluğu açık demektir, yani kayıt aksini söylemedikçe fatura e-postası üretilen belgeyi ekler.
- **variables**: Yalnızca düzenleyici meta verisi. Operatörün düzenleme sırasında gördüğü rozet listesini doldurur ve mesaj üretilirken hiç okunmaz. Güncelliğini yitirmiş bir liste operatörü yanıltır ama hiçbir şeyi bozmaz.

### Bir Mesajı Doğrudan Üretmek

Dispatch bunu alıcı başına bir kez çağırır. Kendiniz yalnızca yapılacak bir dispatch olmadığında çağırın: ham adres listesi ya da değişkenleri zaten elinizde tuttuğunuz her durum.

```php
public static function notifications(
    $type = 'mail',            // 'mail' | 'email' (eşanlamlı) | 'sms' — .html ya da .txt seçer
    $template_name = '',       // "grup/ad", uzantısız
    $content = '',             // gövde geçilirse dosya OKUNMAZ, o gövde render edilir
    $variables = [],           // sizin değişkenleriniz; platformunkiler üstüne eklenir
    $lang = '',                // boşsa o an seçili dile düşer
    $user = 0                  // müşteri kimliği her user_* değişkenini hesaptan doldurur
): array;                      // ['content' => ..., 'subject' => ...]; başarısızlıkta BOŞ dizi
```

- **hata sinyali dönüş değeridir**: Boş dizi, dosyanın bulunamadığı ya da boş olduğu anlamına gelir. Ne istisna ne de log satırı vardır; yani kontrol etmeyen bir çağıran hiçbir şey göndermeden başarı bildirir.
- **üstüne ne ekleniyor**: Logolar, renkler, site başlığı, şirket bilgileri, iletişim bağlantısı, içinde bulunulan yıl ve müşteri kimliği geçildiyse alıcının tüm profili. Sizin değişkenleriniz bunların hiçbirini yenmez, o yüzden adlarını yeniden kullanmayın.
- **render etmek göndermek değildir**: Çağrı biten bir gövde döner; kurulumdan hiçbir şey ayrılmamıştır. Sonucu, bekleyebilir olup olmamasına göre kuyruğa ya da düşük seviyeli göndericiye teslim edin.

## Örnek

Eksiksiz bir olay, platformun okuduğu sırayla.

```json
{"subject":"{$service_name} kotasının %{$quota_percent} kadarını kullandı"}
```

```smarty
<!-- kabuk dış tabloyu açık bıraktı: sürdürün, yeniden açmayın -->
<tbody>
<tr>
  <td>
    <p>Sayın <strong>{$user_greeting_name}</strong>,</p>
    <p>{$service_name}, {$service_domain} üzerinde kotasının %{$quota_percent} kadarını kullandı.</p>
  </td>
</tr>

<!-- Koşullar ve döngüler yorumlara sarılır, böylece görsel düzenleyici onlara dokunmaz.
     Motor yine de çalıştırır; alıcıya yalnız yorum işaretleri ulaşır. -->
<!-- {if $quota_percent >= 100} -->
<tr>
  <td><p>Kota yükseltilene kadar yeni yüklemeler reddedilecek.</p></td>
</tr>
<!-- {/if} -->

<tr>
  <td>
    <!-- theme_color1 yalnız rakamları taşır, işaretçi burada yazılır.
         Buton bgcolor'lı iç içe bir tablodur: posta istemcileri CSS arka planını atar. -->
    <table border="0" cellpadding="0" cellspacing="0" bgcolor="#{$theme_color1}">
      <tbody><tr>
        <td align="center"><a href="{$service_detail_link}">Hizmeti aç</a></td>
      </tr></tbody>
    </table>
  </td>
</tr>
</tbody>
```

```php
// coremio/helpers/notification.php, resolve_service_context() içinde.
// service_name, service_domain ve service_detail_link switch'ten önce zaten
// kuruluyor; içine yalnız bu olaya özgü olan girer.
switch ($name) {
    case 'acme-quota-reached':
        $variables['quota_percent'] = (int) ($context['percent'] ?? 0);
        break;
}
```

```php
// 'entity' her çözümleyicinin kabul ettiği anahtardır; her grup ayrıca kendi
// eşanlamlısını alır ('invoice', 'service', 'order', 'ticket'). Satır da kimlik de olur.
$result = \Notification::dispatch('service', 'acme-quota-reached', [
    'entity'  => $service,
    'percent' => 92,
]);

// Dönüşü asla boolean gibi ele almayın. 'disabled' operatörün olayı kapattığı
// anlamına gelir ve hata değildir; 'error' çözümleyicinin kuramadığını söyler.
if (($result['status'] ?? '') === 'error')
    Logger::getInstance()->warning('kota bildirimi kurulamadi', [
        'service_id' => $service['id'],
        'message'    => $result['message'] ?? '',
    ]);
```

## Tuzaklar

> **Hiçbir şey sizin için kaçışlanmaz**
> 
> Bu motor değerleri geldikleri gibi, işaretleme dahil yazar; varsayılan olarak kaçış uygulayan tema motorunun tersine. Bir müşterinin ya da üçüncü tarafın yazdığı her şey, e-posta gövdesine ulaşmadan önce escape değiştiricisinden geçmelidir. Başta talep mesajları.

> **Bazı değişkenler gerçek kimlik bilgisidir**
> 
> Hizmet değişken kümesi, çözülmüş hesap parolasını ve sunucu girişini içerir. Bunu basmak, çalışan bir kimlik bilgisini bir gelen kutusuna ve mail loguna kalıcı olarak yazmaktır. Bunun yerine hizmet sayfasına bağlantı verin ve kimlik bilgisini yalnızca tüm amacı onu iletmek olan tek mesaja saklayın.

> **Düzgün görünen bir önizleme sandığınızdan azını kanıtlar**
> 
> Önizleme kendi örnek değerlerini kurar ve çözümleyiciyi hiç çağırmaz; yani kimsenin sağlamadığı değişkenlerle dolu bir gövde orada yine kusursuz görünür. Bağlantıyı yalnız gerçek bir dispatch kanıtlar.

> **Tek olay, birden çok gövde**
> 
> Şablon alıcı başına bir kez, o alıcının kendi dilinde okunur. Bir müşteri olayının personel kopyası da aynı dosyadan aynı sözcüklerle üretilir. Sadece müşteriye hitap ederken anlamlı olan cümlelerden kaçının.

## İlgili Makaleler

- [Bildirim Şablonları Nasıl Çalışır](https://dev.wisecp.com/tr/bildirim-sablonlari-nasil-calisir)
- [Bildirim Şablonu Değişkenleri](https://dev.wisecp.com/tr/bildirim-sablonu-degiskenleri)
- [SMS Şablonu Yazma](https://dev.wisecp.com/tr/sms-sablonu-yazma)
- [Mail Modülü Yazma](https://dev.wisecp.com/tr/mail-modulu-yazma)
- [Çeviriler ve Dil Dosyaları](https://dev.wisecp.com/tr/ceviriler-ve-dil-dosyalari)
