In un precedente articolo ho parlato di come scrivere un’application resource per Zend Framework per utilizzare il plugin ZFDebug. In questo articolo vedremo come utilizzare lo stesso meccanismo per un’operazione più semplice ma di utilizzo molto più frequente, ovvero configurare il default transport per l’invio di messaggi di posta elettronica tramite il componente Zend_Mail.
Normalmente per configurare l’invio dei messaggi si utilizza il seguente codice (ad esempio nel bootstrap):
$config = array('auth' => 'login',
'username' => 'myusername',
'password' => 'password');
$transport = new Zend_Mail_Transport_Smtp('mail.server.com', $config);
Zend_Mail::setDefaultTransport($transport);
Per liberarci di questo codice in ogni applicazione che utilizzi la classe Zend_Mail ho scritto una classe Application Resource da inserire nella propria libreria. Il codice della classe è piuttosto semplice
/**
* Resource for creating smtp transports
*
* @uses Zend_Application_Resource_ResourceAbstract
* @category Zend
* @package Zend_Application
* @subpackage Resource
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zenit_Application_Resource_Smtp extends Zend_Application_Resource_ResourceAbstract {
/**
* Transport
*
* @var Zend_Mail_Transport_Abstract
*/
protected $_transport = null;
/**
* Parameters to use
*
* @var array
*/
protected $_params = array ();
/**
* Server name
*
* @var string
*/
protected $_server = '127.0.0.1';
/**
* @var string
*/
protected $_transportClass;
/**
* Set the adapter params
*
* @param $params array
*/
public function setParams(array $params) {
$this->_params = $params;
return $this;
}
/**
* Validates the hostname provided as server
*
* @param string $server
*/
public function setServer($server) {
if (Zend_Validate::is($server, 'Hostname')) {
$this->_server = $server;
} else {
throw new Zend_Mail_Exception("Invalid server name $server");
}
}
/**
* Returns the hostname for the server
*
* @return string
*/
public function getServer() {
return $this->_server;
}
/**
* Transport parameters
*
* @return array
*/
public function getParams() {
return $this->_params;
}
/**
* Determine the type of transport to use
*
* @param string $class
* @throws Zend_Mail_Transport_Exception if the given class doesn't exists
*/
public function setTransport($class) {
if (false === strpos($class, '_')) {
// allow short names such as smtp
$class = 'Zend_Mail_Transport_' . ucfirst($class);
}
if (!class_exists($class)) {
throw new Zend_Mail_Transport_Exception(
"Unexistant transport class $class");
}
$this->_transportClass = $class;
}
/**
* Return the transport class to use
*
* @return null|Zend_Mail_Transport_Abstract
*/
public function getTransport() {
if (null == $this->_transport && $this->_transportClass) {
$class = $this->_transportClass;
// instantiate class
switch ($class) {
case 'Zend_Mail_Transport_Smtp':
case 'Zenit_Mail_Transport_Smtp':
$transport = new $class($this->getServer(),
$this->getParams());
break;
case 'Zend_Mail_Transport_Sendmail':
default:
$transport = new $class();
break;
}
// check transport type
if (!$transport instanceof Zend_Mail_Transport_Abstract) {
throw new Zend_Mail_Transport_Exception(
"Class $class is not a valid Zend_Mail_Transport_Abstract");
}
// set transport as default transport
Zend_Mail::setDefaultTransport($transport);
// assign it to local field
$this->_transport = $transport;
}
return $this->_transport;
}
/**
* Defined by Zend_Application_Resource_Resource
*
* @return null|Zend_Mail_Transport_Abstract
*/
public function init() {
return $this->getTransport();
}
}
Come nel caso precedente, è sufficiente inserire questa classe nel proprio include_path e cambiare/registrare il namespace della libreria (nel mio caso Zenit).
Fatto ciò per configurare il trasporto da usare usando il file application.ini è sufficiente inserire queste righe:
; smtp stuff resources.smtp.transport = "smtp" resources.smtp.server = "smtp.example.org" resources.smtp.params.auth = "login" resources.smtp.params.username = "myusername" resources.smtp.params.password = "mypassword"
Et voilà, il gioco è fatto. Ora si può usare in qualsiasi punto della propria applicazione la classe Zend_Mail per l’invio di messaggi ed il metodo di invio usato sarà quello configurato tramite il file application.ini.
È possibile usare anche classi personalizzate come transport, è sufficiente che tali classi estendano la classe Zend_Mail_Transport_Abstract e che prevedano un costruttore vuoto (in alternativa è necessario personalizzare il metodo getTransport per adattarlo alle proprie esigenze). Per utilizzare una classe personalizzata è sufficiente passare il nome completo della classe come valore dell’opzione resources.smtp.transport, mentre per le classi predefinite si può anche usare il nome breve della classe senza il namespace completo (nell’esempio “smtp”).
Se il server smtp non necessita di autenticazione per l’invio è sufficiente rimuovere le relative righe dal file di configurazione (4-6).
Per quanto mi riguarda attualmente sto utilizzando come transport l’estensione della classe Zend_Mail_Transport_Smtp consigliatami in questo thread del forum di Zend_Framework, in quanto la classe originale soffre di un memory leak nel momento in cui si invia un numero consistente di email nello stesso script, a causa di un log interno che viene salvato in una stringa in memoria. Non appena verrà rilasciato l’aggiornamento che includa la correzione discussa qui, tornerò ad usare la classe ufficiale (di conseguenza la linea case 'Zenit_Mail_Transport_Smtp': nel metodo getTransport verrà rimossa dal codice).




















PERDONAMI,
ma non ho capito dove salvare la classe.
grazie
carlo
Correggimi se ho sbagliato:
ho rinominato la classe in MyApplication_Resource_Smtp e salvato all’interneto di library:
– Library
– MyApplication
– Resource
– Smtp.php
dovrebbe funzionare vero ??
mi dici come dovrei utilizzare la classe ??
Grazie.
Nella situazione che mi dici ci sono altre due condizioni necessarie affinché l’autoloader riconosca la classe:
includePaths.library = APPLICATION_PATH "/library"in application.ini)autoloadernamespaces.myapp = "MyApplication_")Se queste due condizioni sono verificate allora per usare la classe è sufficiente che tu inserisca nel tuo application.ini le seguenti righe con i parametri del tuo mail server nella sezione che preferisci (solitamente basta metterle nella sezione production):
; smtp stuff
resources.smtp.transport = "smtp"
resources.smtp.server = "smtp.example.org"
resources.smtp.params.auth = "login"
resources.smtp.params.username = "myusername"
resources.smtp.params.password = "mypassword"
Fammi sapere se hai problemi
Perfetto.
Le due condizioni erano già soddisfatte.
mi sono sfuggite le righe del file di configurazione
Ora voglio mandare un email…utilizzando la funzione preventiviAction().
quale’ il passo successivo ??
Ciao
Bene, quindi se l’applicazione carica senza problemi a questo punto per inviare un’email è sufficiente il seguente codice
$mail = new Zend_Mail();
$mail->setFrom('info@example.com', 'Nome visualizzato');
$mail->setSubject('Oggetto del messaggio');
$mail->addTo('dest@example.com');
$mail->setBodyText('Corpo del messaggio');
$mail->send();
in qualsiasi punto della tua applicazione.
mmm..no, l’applicazione non viene caricata.
ricevo questo msg di errore:
Fatal error: Uncaught exception ‘Zend_Application_Bootstrap_Exception’ with message ‘Unable to resolve plugin “smtp”; no corresponding plugin with that name’ in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application\Bootstrap\BootstrapAbstract.php:330 Stack trace: #0 C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application\Bootstrap\BootstrapAbstract.php(379): Zend_Application_Bootstrap_BootstrapAbstract->getPluginResource(’smtp’) #1 C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application\Bootstrap\BootstrapAbstract.php(391): Zend_Application_Bootstrap_BootstrapAbstract->getPluginResources() #2 C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application\Bootstrap\BootstrapAbstract.php(618): Zend_Application_Bootstrap_BootstrapAbstract->getPluginResourceNames() #3 C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application\Bootstrap\BootstrapAbstract.php(579): Zend_Application_Bootstrap_BootstrapAbstract->_bootstrap(NULL) #4 C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application.php(347): Zend_Application_Bootstrap_Bo in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application\Bootstrap\BootstrapAbstract.php on line 330
ho salvato la classe smtp.php nel percorso:
library\MyApplication\Application\Resource
ciao e grazie
facendo delle prove, mi risulta che esce qst msg di errore, se in application.ini scrivo:
resources.smtp.transport = “smtp”
resources.smtp.server = “smtp.example.org”
resources.smtp.params.auth = “login”
resources.smtp.params.username = “myusername”
resources.smtp.params.password = “mypassword”
inoltre, utilizzando ZFDebug v1.5 ho notato che la classe MyApplication_Application_Resource_Smtp non viene caricata.
Chiaro, ho dimenticato di indicarti una direttiva… Devi aggiungere anche questa all’application.ini in modo da indicare a ZF che le tue classi sono usate come application resources:
pluginPaths.MyApplication_Application_Resource = "MyApplication/Application/Resource"Così dovrebbe andare.
bene..ora non ricevo alcune messaggio di errore, in fase di caricameto.
ma quando eseguo la funziona… ricevo qst msg di errore:
Zend_Mail_Protocol_Exception: Impossibile stabilire la connessione. Risposta non corretta della parte connessa dopo l’intervallo di tempo oppure mancata risposta dall’host collegato.
thrown in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail\Protocol\Abstract.php on line 234
Call Stack
Zend_Mail_Protocol_Abstract->_connect()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail\Protocol\Smtp.php on line 167
Zend_Mail_Protocol_Smtp->connect()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail\Transport\Smtp.php on line 195
Zend_Mail_Transport_Smtp->_sendMail()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail\Transport\Abstract.php on line 348
Zend_Mail_Transport_Abstract->send()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail.php on line 973
Zend_Mail->send()
in C:\xampp\htdocs\lavoro\MyWebSite\application\controllers\IndexController.php on line 182
IndexController->preventivoAction()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Controller\Action.php on line 513
Zend_Controller_Action->dispatch()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Controller\Dispatcher\Standard.php on line 289
Zend_Controller_Dispatcher_Standard->dispatch()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Controller\Front.php on line 946
Zend_Controller_Front->dispatch()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application\Bootstrap\Bootstrap.php on line 77
Zend_Application_Bootstrap_Bootstrap->run()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application.php on line 358
Zend_Application->run()
in C:\xampp\htdocs\lavoro\MyWebSite\index.php on line 31
Domanda: puà essere che sto testando la funziona in locale ???
Ottimo, manca poco… Dall’errore che ricevi direi che si tratta di un timeout nella connessione al server smtp. Nel file application.ini hai lasciato i dati che ho postato nell’esempio (ovvero smtp.example.com)? In tal caso è quello il problema, i dati li devi sostituire con i dati del tuo server smtp. A seconda di dove farai girare l’applicazione variano, ma in ogni caso per la fase di sviluppo puoi tranquillamente utilizzare il server smtp del tuo provider. In alternativa puoi usare un server smtp di qualche provider italiano, ad esempio se hai un indirizzo di posta di tiscali (o se ne vuoi creare uno per tale scopo) puoi mettere smtp.tiscali.it come server, l’indirizzo che hai creato come username, e la password scelta come password.
Ke sfista, ho dimenticato di sostiuire i dati
ho lanciato l’applicazione, questa volta ricevo qst msg di errore:
Zend_Mail_Protocol_Exception: 530 5.7.0 Must issue a STARTTLS command first. c28sm18966336fka.19
thrown in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail\Protocol\Abstract.php on line 378
Call Stack
Zend_Mail_Protocol_Abstract->_expect()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail\Protocol\Smtp\Auth\Login.php on line 91
Zend_Mail_Protocol_Smtp_Auth_Login->auth()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail\Protocol\Smtp.php on line 217
Zend_Mail_Protocol_Smtp->helo()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail\Transport\Smtp.php on line 196
Zend_Mail_Transport_Smtp->_sendMail()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail\Transport\Abstract.php on line 348
Zend_Mail_Transport_Abstract->send()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Mail.php on line 973
Zend_Mail->send()
in C:\xampp\htdocs\lavoro\MyWebSite\application\controllers\IndexController.php on line 182
IndexController->preventivoAction()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Controller\Action.php on line 513
Zend_Controller_Action->dispatch()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Controller\Dispatcher\Standard.php on line 289
Zend_Controller_Dispatcher_Standard->dispatch()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Controller\Front.php on line 946
Zend_Controller_Front->dispatch()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application\Bootstrap\Bootstrap.php on line 77
Zend_Application_Bootstrap_Bootstrap->run()
in C:\xampp\htdocs\lavoro\MyWebSite\library\Zend\Application.php on line 358
Zend_Application->run()
in C:\xampp\htdocs\lavoro\MyWebSite\index.php on line 31
questi sono i dati che sto utilizzando:
resources.smtp.transport = “smtp”
resources.smtp.server = “smtp.gmail.com”
resources.smtp.params.auth = “login”
resources.smtp.params.username = “miousername”
resources.smtp.params.password = “miapassword”
Ops’…. sfista => svista
scusatemi.
Se usi gmail devi abilitare tls altrimenti non ti fa inviare in chiaro, lo puoi fare aggiungendo all’application.ini la seguente riga:
resources.smtp.params.ssl = "tls"oltre alle righe già presenti. Fatto questo sei a posto, appena testato con il mio account gmail per sicurezza, vai tranquillo.
Problema risolto.
dopo tanti tentativi sono arrivato ad una conclusione:
la classe funziona alla perfezione, anche in locale,
ma non con il server di posta gmail.com ( mi dà problemi)
ho provato ad utilizzare il server di posta di yahoo e l’email viene inviata correttamente.
grande, funziona!!
grazie a te!!!
Carlo
Se inserisci la direttiva del mio commento precedente funziona anche con gmail
A presto.
Scusami,
non avevo letto la tua risposta.
Ho aggiunto la riga che mi hai consigliato di utilizzare e, ora anche con gmail funziona alla grande.
Grazie di tutto
Alla prossima.
Carlo