Clicky

Skocz do zawartości


Zdjęcie
- - - - -

[K2] Wysyłanie maili (swift mailer) - helper

19 odpowiedzi w tym temacie

  • Zaloguj się, aby dodać odpowiedź

#1 cmike

cmike

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 132 postów
  • Skąd:Krk

Napisano 17 styczeń 2008 - 10:13

Na podstawie wątku na forum Kohany


Aby skorzystać z nieobecnej w Kohanie funkcji wysyłania maili (dostępnej w CI) należy skorzystać z udostępnionego razem z Kohaną narzędzie SwiftMailer. Na forum Kohany zostało zaprezentowane ułatwienie pozwalające w prosty sposób skorzystać z tego narzędzia. Wystarczy w katalogu application/helpers utworzyć plik mail.php z zawartością:
<?php defined('SYSPATH') or die('No direct script access.');
/*
 * Class: mail
 *  A basic wrapper for Swiftmailer.
 */
class mail {

	/*
	 * Method: swift
	 *  Creates a Swift object with connections.
	 *
	 * Returns:
	 *  A new Swift object.
	 */
	public static function swift()
	{
		static $run;
		
		// Only include Swift files once
		if ($run !== TRUE)
		{
			include Kohana::find_file('vendor', 'swift/Swift');
			include Kohana::find_file('vendor', 'swift/Swift/Connection/SMTP');
			include Kohana::find_file('vendor', 'swift/Swift/Connection/NativeMail');
			include Kohana::find_file('vendor', 'swift/Swift/Connection/Multi');
			
			$run = TRUE;
		}
		
		// SMTP connection
		$smtp = new Swift_Connection_SMTP(Config::item('mail.smtp_host'));
		$smtp->setUsername(Config::item('mail.smtp_user'));
		$smtp->setPassword(Config::item('mail.smtp_pass'));
		$connections[] = $smtp;
		
		// PHP's native mail function as fallback
		$connections[] = new Swift_Connection_NativeMail();

		// Test connection
		try
		{
			$swift = new Swift(new Swift_Connection_Multi($connections));
		}
		catch (Swift_ConnectionException $exception)
		{
			// TODO: lang file, more descriptive text
			Kohana::show_error('swift.no_connection', 'Check your mail connection settings.');
		}

		// Return Swift instance
		return $swift;
	}

	/*
	 * Method: send
	 *  Sends a mail.
	 * 
	 * Parameters:
	 *  to      - one or more recipients (RFC 2822 string)
	 *  subject - mail subject
	 *  message - mail body
	 *  from    - sender (RFC 2822 string)
	 *  html    - set to TRUE if you want to send HTML mails
	 *
	 * Returns:
	 *  An integer: the number of successful recipients.
	 */
	public static function send($to, $subject, $message, $from, $html = FALSE)
	{
		// Load Swiftmailer
		$swift = self::swift();

		// Message
		$message = new Swift_Message
		(
			(string) $subject,
			(string) $message,
			($html) ? 'text/html' : 'text/plain',
			'8bit',
			'utf-8'
		);

		// Recipient(s)
		$to = self::parse_rfc2822($to);

		if (empty($to))
			return FALSE;

		$recipient = new Swift_RecipientList;

		foreach ($to as $address)
		{
			$recipient->addTo($address[0], $address[1]);
		}

		// Sender
		$from = self::parse_rfc2822($from);

		if (empty($from))
			return FALSE;

		$sender = new Swift_Address($from[0][0], $from[0][1]);

		// Send it!
		return $swift->send($message, $recipient, $sender);
	}

	/*
	 * Method: parse_rfc2822
	 *  Parses RFC 2822 compliant email strings.
	 * 
	 * Parameters:
	 *  str - email string like 'User <user@example.com>, ...'
	 *
	 * Returns:
	 *  A nested array containing email addresses and names.
	 */
	public static function parse_rfc2822($str)
	{
		$return = array();

		foreach (explode(',', (string) $str) as $email)
		{
			$email = trim($email);

			if (valid::email($email))
			{
				$return[] = array($email, '');
			}
			elseif (preg_match('/^(.*)<(\S+)>$/', $email, $matches) AND valid::email($matches[2]))
			{
				$return[] = array($matches[2], trim($matches[1]));
			}
		}

		return $return;
	}

} // End mail
?>

Po utworzeniu helpera należy utworzyć w katalogu application/config pliku konfiguracyjnego mail.php z zawartością:
<?php defined('SYSPATH') or die('No direct script access.');
/*
 * File: config.php
 *  This configuration file is unique to every application.
 *
 * Options:
 *  smtp_host			- smpt host address
 *  smtp_user			- smtp username
 *  smtp_pass			- smtp password 
 */
$config = array
(
	'smtp_host'				=> 'smtp.strona.com',
	'smtp_user'				=> 'username',
	'smtp_pass'				=> 'magic'
);
?>

W momencie, kiedy chcemy skorzystać z funkcji wysyłania maili wystarczy w kontrolerze dodać kod:
<?php defined('SYSPATH') or die('No direct script access.');
...
...
...
$this->load->helper('mail');
...
...
// Dla maili w czystym tekście
mail::send('adres@odbiorcy.pl', 'Tytul maila', 'Tresc maila', 'adres@nadawcy.pl', FALSE);
// Dla maili w HTMLu
mail::send('adres@odbiorcy.pl', 'Tytul maila', '<body><b>Tresc maila</b></body>', 'adres@nadawcy.pl', TRUE);
...
...
?>

i voila...

#2 AvantaR

AvantaR

    Początkujący

  • Użytkownik
  • Pip
  • 78 postów
  • Skąd:Łaziska Górne

Napisano 30 styczeń 2008 - 14:25

Dzieki, na pewno sie przyda :)
Gory wysokie, kto mi z Wami walczyc kaze?

#3 mariusz

mariusz

    Początkujący

  • Użytkownik
  • Pip
  • 7 postów

Napisano 08 listopad 2008 - 03:21

A jak dodać wysyłanie załączników do tej klasy?

#4 Zepco

Zepco

    Senior Mastah

  • Moderator
  • 1583 postów
  • Skąd:Kielce

Napisano 08 listopad 2008 - 09:22

Zerknij tutaj http://forum.kohanap...9&page=1#Item_0

Tak na marginesie, to helper email już dawno jest dołączany do kohany, także trzeba tylko ustawić konfigurację i używać poprzez email::

OŚWIADCZENIE: Ja, niżej podpisany, świadomy wszystkich konsekwencji tego posta postanawiam go dopuścić do użytku publicznego, albowiem bo gdyż aczkolwiek uważam, że nie wyrządzi on (znaczy: post) krzywdy nikomu innemu niźli mnie samemu (czyli autorowi posta).
-- Zepco --


#5 jedre

jedre

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 464 postów
  • Skąd:Polska

Napisano 11 grudzień 2008 - 13:19

W jaki sposób wysyłać poprzez pole "bcc" i zmienić pole "odpowiedz do". Oczywiście przy użyciu helpera email i swiftmailera.

#6 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 11 grudzień 2008 - 14:44

Może komuś przyda się moja idea wykorzystania wysyłki maila. Wszystkie maile, które są wysyłane w systemie gromadzę w jednej klasie:
application/helpers/my_email.php:
<?php
class email extends email_Core {
public static function send($to, $subject, $template, array $params) {
$message = new View($template, $params);

parent::send($to, 'nadawca@serwis.pl', 'Serwis - '.$subject, $message);
}

/**
* Wysyła maila służącego do aktywacji konta.
*
* Parametry $params: username, ticket
*
* @param string $to
* @param array $params
*/
public static function activate($to, array $params) {
self::send($to, 'aktywacja konta', 'registration/mail/activate', $params);
}

/**
* Wysyła ponownie maila z linkiem aktywacyjnym
*
* @param string $to
* @param array $params
*/
public static function resendTicket($to, array $params) {
self::send($to, 'link aktywacyjny', 'registration/mail/resend_ticket', $params);
}
}

Jak widać treść maila jest pobierana z pliku jako widok, po czym przyspisywane są do niego konkretne parametry. Realizacja wysyłki danego maila sprowadza się do (w jakimś kontrolerze):
email::activate($data['email'], array(
'username' => $data['username'],
'ticket' => $data['ticket']
));

gdzie tablica $data to dane wpisane podczas rejestracji (oprócz $data['ticket'], która jest losowa). Następnie w szablonie wywoływanym w email::activate() jako 'registration/mail/activate' tworzymy normalny widok czyli:
application/views/registration/mail/activate.php
Witaj <?= $username ?>!

Na Twój adres e-mail dokonano rejestracji konta w serwisie Serwis.pl.

W celu pełnej aktywacji konta kliknij w poniższy link:
http://serwis.pl/registration/activate.html?username=<?= $username ?>&ticket=<?= $ticket ?>

Jeżeli nie rejestrowałeś się w serwisie zignoruj tego maila, a konto zostanie automatycznie usunięte po upływie 24 godzin.

Co na tym wszystkim zyskujemy? Przede wszystkim wyciągnięcie treści maila do osobnego szablonu. Ponadto definicję nadawcy oraz tytułów maili w jednym miejscu. W momencie wysyłki kilku takich samych maili z kilku akcji nie musimy dublować kodu.

Co sądzicie o takim rozwiązaniu?
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#7 jedre

jedre

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 464 postów
  • Skąd:Polska

Napisano 16 grudzień 2008 - 21:05

Jak powinna wyglądać lista emailu (tablica) jeśli chcę wysłać wiadomość do więcej niż jednej osoby?
Oczywiscie korzystam ze swiftmailera i standardowego helpera email::send

#8 thejw23

thejw23

    Senior Mastah

  • Webmastahy
  • PipPipPip
  • 824 postów

Napisano 16 grudzień 2008 - 21:21

wydaje mi sie, ze skoro jednego adresata podaje sie jako string, dokumentacja podaje:
$to      = 'to@example.com';  // Address can also be array('to@example.com', 'Name')

zrodla mowia: 
@param mixed The recipients to send to.  Can be a string, Swift_Address or Swift_RecipientList.


to powinno zadzialac:

$rec = array();
$rec[] = 'adres@email.com';
$rec[] = 'adres2@email.com';
//lub
$rec[] = array('adres3@email.com','darth');
$rec[] = array('adres4@email.com','anakin');


ew. moze zgodnie ze specyfikacja swift`a http://www.swiftmail...ending/multiple

#9 jedre

jedre

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 464 postów
  • Skąd:Polska

Napisano 16 grudzień 2008 - 21:33

Nie działa, mail dochodzi tylko na jeden adres, w pierwszym przypadku adres wygląda:
adres@email.com <adres2@email.com> czyli dochodzi  na adres: adres2@email.com
w drugim wypadku:
Array <adres4@email.com> czyli mail dochodzi na: adres4@email.com

a adres 3 całkiem coś wcina.

Analizując email::send jest tam błąd. Wygląda mi na to, że foreach zawsze wykona się tylko raz.

#10 jedre

jedre

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 464 postów
  • Skąd:Polska

Napisano 16 grudzień 2008 - 22:05

Bez modyfikacji helpera się nie obeszło. Poniżej oryginalny fragment metody send i zmodyfikowany:

Oryginalny:
foreach ($to as $method => $set)
{
if ( ! in_array($method, array('to', 'cc', 'bcc')))
{
// Use To: by default
$method = 'to';
}

// Create method name
$method = 'add'.ucfirst($method);

if (is_array($set))
{
// Add a recipient with name
$recipients->$method($set[0], $set[1]);
}
else
{
// Add a recipient without name
$recipients->$method($set);
}
}


Zmodyfikowany:
foreach ($to as $method => $set)
{
if ( ! in_array($method, array('to', 'cc', 'bcc')))
{
// Use To: by default
$method = 'to';
}

// Create method name
$method = 'add'.ucfirst($method);

foreach($set as $val)
{
if (is_array($val))
{
// Add a recipient with name
$recipients->$method($val[0], $val[1]);
}
else
{
// Add a recipient without name
$recipients->$method($val);
}
}
}


Zabrakło im jednego foreacha. Lista adresów może wyglądać tak:
$list = array('to' => array(
   'ad@ma.com',
   'ad2@ma.com',
   'ad3@ma.com'
);


lub

$list = array('to' => array(
   array('ad@ma.com', 'Name1'),
   array('ad2@ma.com', 'Name2'),
   array('ad3@ma.com', 'Name3')
);


lub mieszana:
$list = array('to' => array(
  'ad@ma.com',
  array('ad2@ma.com', 'Name2')
);


#11 thejw23

thejw23

    Senior Mastah

  • Webmastahy
  • PipPipPip
  • 824 postów

Napisano 17 grudzień 2008 - 01:07

no prosze, dobrze wiedziec.  zastanawiam sie tylko, czy zamiast dodawac foreach nie wystarczy wywalic

			if (isset($to[0]) AND isset($to[1]))
{
// Create To: address set
$to = array('to' => $to);
}


jest pozno i nie do konca rozumiem czemu wlasciwie ten kod ma wogole sluzyc. raczej on tu miesza i bez niego powinno dzialac prawidlowo. z ciekawosci jutro sprawdze :)

#12 jedre

jedre

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 464 postów
  • Skąd:Polska

Napisano 17 grudzień 2008 - 09:51

Ze względu na to, że możemy określać w jaki sposób (to, cc, bcc) chcemy wysłać maila, to w przypadku istnienia takiej tablicy:

array('ad@em.com', ad2@em.com');

Array
(
    [0] => ad@em.com
    [1] => ad2@em.com
)


poniższy kod ma sens.

if (isset($to[0]) AND isset($to[1]))
{
    // Create To: address set
    $to = array('to' => $to);
}


w przypadku istnienia takiej tablicy:

array('bcc' => array('ad@em.com', 'ad2@em.com'))

Array
(
    [bcc] => Array
        (
            [0] => ad@em.com
            [1] => ad2@em.com
        )

)


Powyższy kod się nawet nie wykona.

Czyli podany przez Ciebie wątpliwy kod pilnuje żeby została wybrana jakakolwiek metoda wysyłania - domyślnie ustawiając na 'to'. W pierwszym foreachu sprawdzane jest czy nie została przypadkiem podana jakaś bzdurna metoda wysłania wiadomości, bo przecież całkiem przypadkiem moglibyśmy zdefiniować taką tablicę:

array('ala' => array('ad@em.com', 'ad2@em.com'));

Array
(
    [ala] => Array
        (
            [0] => ad@em.com
            [1] => ad2@em.com
        )

)


Wtedy ten kod:

if (isset($to[0]) AND isset($to[1]))
{
    // Create To: address set
    $to = array('to' => $to);
}


już nie zadziała.

Za to zadziała ten:

if ( ! in_array($method, array('to', 'cc', 'bcc')))
{
    // Use To: by default
    $method = 'to';
}


Poprawna metoda jest ważna ponieważ na jej podstawie budujemy nazwę funkcji które występują w swiftmailerze a mogą to być:

  • addTo
  • addCc
  • addBcc

Z tym że mając tablicę o powyższej strukturze potrzebny nam jest jeszcze jeden foreach :)
Ciekawe czy już ktoś gdzieś miał taki problem i zgłosił to do temu kohany.

#13 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 17 grudzień 2008 - 11:08

a nie powinno być czasem tak:
foreach ($to as $method => $set)
{
if ( ! in_array($method, array('to', 'cc', 'bcc')))
{
// Use To: by default
$method = 'to';
}

// Create method name
$method = 'add'.ucfirst($method);


if (is_array($set))
{
foreach($set as $val)
{
if (is_array($val))
{
// Add a recipient with name
$recipients->$method($val[0], $val[1]);
}
else
{
// Add a recipient without name
$recipients->$method($val);
}
}
}
else
{
// Add a recipient without name
$recipients->$method($set);
}
}

?

#14 jedre

jedre

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 464 postów
  • Skąd:Polska

Napisano 17 grudzień 2008 - 11:17

Fakt, bo przecież może istnieć lista (tablica):
array('to' => 'ad@em.com')


choć wątpię, żeby ktoś tak pisał. Niemniej jednak jest to zabezpieczenie przed błędem :)

#15 jedre

jedre

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 464 postów
  • Skąd:Polska

Napisano 12 luty 2009 - 23:12

Dzisiaj zassałem nową paczkę wersji 2.3.1 i widzę ze helper email ciągle działa na jednym foreach'u, czyżby nie byli świadomi takiego błędu lub nie wysyłali przy pomocy tej funkcji wiadomości do więcej niż jednej osoby naraz?

A może nie ma żadnego błędu i sobie coś uroiliśmy? (a właściwie to ja ;P)

#16 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 12 luty 2009 - 23:15

a zgłosiłeś im to? :)

#17 jedre

jedre

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 464 postów
  • Skąd:Polska

Napisano 12 luty 2009 - 23:28

Szczerze mówiąc nie czuję się na siłach aby zgłaszać błędy. Z tym że to tak powszechny błąd (o ile istnieje) że już dano powinien być wykryty przynajmniej przez tuzin osób i zgłoszony.

Zaczynam wątpić w istnienie błędu, uhm :|

#18 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 12 luty 2009 - 23:55

no wiesz jakby wszyscy mieli takie podejście... ;)

#19 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 13 luty 2009 - 08:35

No przecież to tylko helper czyli klasa, która upraszcza wykonywanie jakiś powtarzalnych czynności. Najczęściej wysyła się maile do jednej osoby (link aktywacyjny, przypomnienie hasła itd). Jeżeli chcesz wysyłać maile do większej liczby osób to albo stwórz sobie własną metodę w helperze albo "ręcznie" buduj obiekty. Ja do wysyłki newslettera korzystam właśnie z tego drugiego rozwiązania:
require Kohana::find_file('vendor', 'swift/Swift');
spl_autoload_register(array('Swift_ClassLoader', 'load'));

$swift = new Swift(new Swift_Connection_NativeMail());
$batch = new Swift_BatchMailer($swift);

$message = new Swift_Message($newsletter_mail[$k]['title'], $newsletter_mail[$k]['content']);
$batch->send($message, $v, Kohana::config('newsletter.from'));

Wszystko działa mniamuśnie :)
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#20 jedre

jedre

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 464 postów
  • Skąd:Polska

Napisano 21 marzec 2009 - 15:42

Post powiązany z:
http://forum.kohanap...99.html#msg3499

Dzisiaj napotkał mnie dziwny problem:
F:/wamp/www/ikkc/system/vendor/swift/Swift/ClassLoader.php [35]:

require_once(F:\wamp\www\ikkc\system\vendor\swift\Swift/../htm.php) [function.require-once]: failed to open stream: No such file or directory

Nie wiem o co mu kaman. Vendory sa Swift jest. Jeszcze wczoraj działało a dzisiaj nie może znaleźć pliku....

Próbuje załadować dziwny plik... \Swift/../htm.php
Klika linijek z: Zrzut stosu (Stack Trace)

system\vendor\swift\Swift\ClassLoader.php [35]:
Swift_ClassLoader::load(  )
Swift_ClassLoader::load( htm )

application\views\email\footer.php [3]:
spl_autoload_call( htm )

Edit:
Jak zwykle sam sobie stworzyłem problem. W widoku który dołączam przy wysyłce maila zrobiłem literówkę zamiast napisać html::anchor(), napisałem htm::anchor() ot to cały problem :)




Użytkownicy przeglądający ten temat: 0

0 użytkowników, 0 gości, 0 anonimowych