Symfony Mailer Exchange mail server - php

Today I'm trying to connect my Symfony application to a local mail server that running as Microsoft Exchange server.
First, before switching to Symfony my web project was developed with Asp.NET, for some personal reasons I refund the project under Symfony.
In C# this code was working correctly :
public static void MailSender(string server, string fromDisplayName, string fromMailAddress, List<List<KeyValuePair<string,string>>> tos, string subject, string body, List<string> attachments = null, List<List<KeyValuePair<string,string>>> ccs = null, List<List<KeyValuePair<string,string>>> bccs = null)
{
using (MailMessage mailMessage = new MailMessage())
{
mailMessage.From = new MailAddress(fromMailAddress, fromDisplayName);
foreach(List<KeyValuePair<string, string>> to in tos){
mailMessage.To.Add(new MailAddress(to[1].Value.ToString(), to[0].Value.ToString()));
}
if (ccs != null){
foreach(List<KeyValuePair<string, string>> cc in ccs){
mailMessage.CC.Add(new MailAddress(cc[1].Value.ToString(), cc[0].Value.ToString()));
}
}
if (bccs != null){
foreach(List<KeyValuePair<string, string>> bcc in bccs){
mailMessage.CC.Add(new MailAddress(bcc[1].Value.ToString(), bcc[0].Value.ToString()));
}
}
mailMessage.Subject = subject;
mailMessage.Body = body;
mailMessage.IsBodyHtml = true;
if (attachments != null)
{
foreach (string attachment in attachments)
mailMessage.Attachments.Add(new Attachment(attachment));
}
using (SmtpClient smtpClient = new SmtpClient(server))
{
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
smtpClient.UseDefaultCredentials = true;
smtpClient.Send(mailMessage);
}
}
}
The server url was in the format: myserver.domain.tld.
Also it used the Windows Integrated Authentication.
How can I configure PHP or Symfony (or both) to work with my local Exchange mail server ?
I tried to use this type of url in MAILER_DSN variable:
smtp://user:pass#myserver.domain.tld (user as email address with '%40' for '#' character.
Thanks.

Sorry for this question cause Its a mistake from me, I put MAILER_DSN=smtp://server.tld:25
Also, I commented a line into config/packages/messenger.yaml
this line: Symfony\Component\Mailer\Messenger\SendEmailMessage: async
This second option solve my problem.
If you had another option, I'm aware about it!
Thks.

Related

Why does the value of the $id variable change to a string automatically on the WAMP server, but not on the Bluehost server?

In PHP, the $id variable is expected to receive an integer value from the client side. However, when the id value is sent as an integer from the client side to the PHP script using the POST request method, it is automatically converted to a string type in PHP when the script is uploaded on the WAMP server. On the other hand, when the script is uploaded on the Bluehost server, the id value remains an integer and is not converted to a string, which is what I want.
Here is a simple PHP script:
<?php
$id = $_POST["id"];
if (is_int($id))
echo "It is integer"; // It will print this if the PHP script was uploaded to the Bluehost server.
else if (is_string($id))
echo "It is string"; // It will print this if the PHP script was uploaded to the WAMP server.
The id value that is sent from the client side is via an Android app, and this is how I send the id value to the PHP script:
RetrofitManager class
public class RetrofitManager {
private static RetrofitManager.Api api;
public static RetrofitManager.Api getApi() {
if (api == null)
api = new Retrofit.Builder()
.baseUrl("http://192.151.5.721/API/")
.client(new OkHttpClient.Builder().readTimeout(3, TimeUnit.MINUTES).writeTimeout(3, TimeUnit.MINUTES).connectTimeout(25, TimeUnit.SECONDS).build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build()
.create(Api.class);
return api;
}
public interface Api {
#FormUrlEncoded
#POST("Countries/Get.php")
Single<CountryModelResponse> getCountries(#Field("id") int countryId);
}
}
CountriesRepository class
public class CountriesRepository {
public LiveData<Object> getCountries(Context context) {
MutableLiveData<Object> mutableLiveData = new MutableLiveData<>();
PublishSubject<String> retrySubject = PublishSubject.create();
RetrofitManager.getApi().getCountries(Navigation.findNavController(MainActivity.activityMainBinding.activityMainFragmentContainerViewContainer).getPreviousBackStackEntry() == null ? SharedPreferencesManager.getIntegerValue(context, SharedPreferencesManager.Keys.COUNTRY_ID.name()) : -1)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(mutableLiveData::setValue)
.doOnError(throwable -> {
LinkedHashSet<Object> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(!Utils.isInternetConnected(context) ? 100 : throwable instanceof SocketTimeoutException ? 200 : 300);
linkedHashSet.add(retrySubject);
mutableLiveData.setValue(linkedHashSet);
})
.retryWhen(throwableFlowable -> throwableFlowable.flatMap(throwable -> retrySubject.toFlowable(BackpressureStrategy.DROP).take(1), (throwable, s) -> s))
.subscribe(countryModelResponse -> {
if (countryModelResponse.getRequestStatus() == 100)
mutableLiveData.setValue(countryModelResponse);
else {
LinkedHashSet<Object> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(300);
linkedHashSet.add(retrySubject);
mutableLiveData.setValue(linkedHashSet);
}
});
return mutableLiveData;
}
}
I'm not sure why this difference in behavior occurs between the two servers.
I'm using the latest version of PHP and the WAMP server.
All the requests over HTTP as sent as strings. We have to cast it according to our needs. In your case the behavior is strange. Try checking the PHP version at both ends and see if they are the same.

Emulating successful send via phpmailer ($mail->Send())

When I'm building and testing my website on local server, I would like to emulate successful sending via phpmailer, so I avoid actually sending emails.
I normally use if ($mail->Send()) { the mail was sent, now do this }.
For local testing I think the best would be to skip the whole phpmailer inclusion, instead of adding a lot of if statements etc.
But skipping phpmailer would then cause php to complain about $mail->Send(), $mail->addAddress('emailaddress') etc.
How could I fake the function (or object/class) so that calls to $mail->Send() are always true, and the rest $mail->something() etc. are just ignored/true, so that no email is sent?
Extend the PHPMailer class and override the public function send().
class UnitTestMailer extends PHPMailer {
public function send() {
return $this;
}
}
class User {
public function __construct(PHPMailer $mailer) {
$this->mailer = $mailer;
}
public function sendActiviation() {
return $this->mailer->send();
}
}
// ... somewhere in your test
public function test_if_from_is_properly_set() {
// ...
$user = new User(new UnitTestMailer);
// ...
$mailer = $user->sendActivation();
$this->assertEquals($expectedFrom, $mailer->From);
}
Why emulate?
I use INI files to provide configuration variables for PHPMailer depending on the environment. Live obviously has the server's mail settings. Local uses my Gmail account credentials to send mail.
You can have the best of both worlds :)
Keep a config.ini file for example somewhere in your working directory (I tend to use root but that's preference) and make sure it's in your .gitignore or similar. Your local version would look something like:
[PHPMailer Settings]
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_SMTPSECURE = "tls"
EMAIL_SMTPAUTH = "true"
EMAIL_USERNAME = "my_email#gmail.com"
EMAIL_PASSWORD = "my_password"
then in your PHP:
$ini = parse_ini_file($_SERVER['DOCUMENT_ROOT'] . "/config.ini", true, INI_SCANNER_TYPED);
// use settings from INI file:
$foo = $ini['PHPMailer Settings']['EMAIL_HOST'];
$bar = $ini['PHPMailer Settings']['EMAIL_PORT'];
Security Bonus
Change the syntax of your INI file to look like the below and rename it to config.ini.php:
; <?php
; die();
; /*
[PHPMailer Settings]
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_SMTPSECURE = "tls"
EMAIL_SMTPAUTH = "true"
EMAIL_USERNAME = "my_email#gmail.com"
EMAIL_PASSWORD = "my_password"
; */ ?>
(remember to use the new filename in your PHP code)
PHP can still parse the settings, but if anyone tried to access the INI file it would be parsed as PHP comments and just show ";"

Azure notifications hub push notification failing or delivering invalid or incomplete data

I am using the following php code to send a push notification to Android application using Azure Notification Hub.
$hub = new NotificationHub("Endpoint=sb://ServiceName.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SharedAccessKey", "ServiceNameNotification");
$message = '{"data":{"message":"This is a sample notification","title":"Sample Notification","action":"Test","action_id":"60"}}';
$notification = new AzureNotification("gcm", $message);
$hub->sendNotification($notification, null);
But unfortunately most of the times the notification is not getting delivered, although I am getting a 201 as the response. Whenever it does get delivered, the results are unpredictable, sometimes the contents of old notifications end up getting shown.
The following code is used to show the notifications in Android app (Xamarin.Android) :
using System;
using Android.App;
using Android.Content;
using Gcm.Client;
using Microsoft.WindowsAzure.MobileServices;
using Newtonsoft.Json.Linq;
using ServiceName.Helpers;
[assembly: Permission(Name = "#PACKAGE_NAME#.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "#PACKAGE_NAME#.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
//GET_ACCOUNTS is needed only for Android versions 4.0.3 and below
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
namespace ServiceName.Droid
{
[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE },
Categories = new string[] { "#PACKAGE_NAME#" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK },
Categories = new string[] { "#PACKAGE_NAME#" })]
[IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY },
Categories = new string[] { "#PACKAGE_NAME#" })]
public class ServiceNameBroadcastReceiver : GcmBroadcastReceiverBase<PushHandlerService>
{
public static string[] senderIDs = new string[] { Constants.SenderID };
public const string TAG = "MyBroadcastReceiver-GCM";
}
// The ServiceAttribute must be applied to the class.
[Service]
public class PushHandlerService : GcmServiceBase
{
public static string RegistrationID { get; private set; }
public PushHandlerService() : base(ServiceNameBroadcastReceiver.senderIDs) { }
protected override void OnMessage(Context context, Intent intent)
{
string message = string.Empty;
string title = string.Empty;
string action = string.Empty;
string action_id = string.Empty;
if (intent.Extras.ContainsKey("title"))
{
title = intent.Extras.Get("title").ToString();
}
if (intent.Extras.ContainsKey("message"))
{
message = intent.Extras.Get("message").ToString();
}
if (intent.Extras.ContainsKey("action"))
{
action = intent.Extras.Get("action").ToString();
}
if (intent.Extras.ContainsKey("action_id"))
{
action_id = intent.Extras.Get("action_id").ToString();
}
// Extract the push notification message from the intent.
if (!string.IsNullOrWhiteSpace(message) || !string.IsNullOrWhiteSpace(title))
{
// Create a notification manager to send the notification.
var notificationManager =
GetSystemService(Context.NotificationService) as NotificationManager;
// Create a new intent to show the notification in the UI.
PendingIntent contentIntent =
PendingIntent.GetActivity(context, 0,
new Intent(this, typeof(MainActivity)), 0);
// Create the notification using the builder.
var builder = new Notification.Builder(context);
builder.SetAutoCancel(false);
if (!string.IsNullOrWhiteSpace(title))
{
builder.SetContentTitle(title);
}
else
{
builder.SetContentTitle("Notification from ServiceName");
}
if (!string.IsNullOrWhiteSpace(message))
{
builder.SetContentText(message);
}
else
{
builder.SetContentText("Hello ServiceName User");
}
builder.SetSmallIcon(Resource.Drawable.ic_stat_icon);
builder.SetContentIntent(contentIntent);
var notification = builder.Build();
// Display the notification in the Notifications Area.
notificationManager.Notify(1, notification);
}
}
protected override void OnError(Context context, string errorId)
{
System.Diagnostics.Debug.WriteLine(
string.Format("Error occurred in the notification: {0}.", errorId));
}
protected override async void OnRegistered(Context context, string registrationId)
{
System.Diagnostics.Debug.WriteLine("The device has been registered with GCM.", "Success!");
// Get the MobileServiceClient from the current activity instance.
MobileServiceClient client = MainActivity.CurrentActivity.CurrentClient;
var push = client.GetPush();
// Define a message body for GCM.
const string templateBodyGCM = "{\"data\":{\"message\":\"$(messageParam)\", \"title\": \"$(titleParam)\", \"action\":\"$(actionParam)\",\"action_id\":\"$(action_idParam)\"}}";
// Define the template registration as JSON.
JObject templates = new JObject();
templates["genericMessage"] = new JObject
{
{"body", templateBodyGCM }
};
try
{
// Make sure we run the registration on the same thread as the activity,
// to avoid threading errors.
MainActivity.CurrentActivity.RunOnUiThread(
// Register the template with Notification Hubs.
async () => {
try
{
await push.RegisterAsync(registrationId, templates);
System.Diagnostics.Debug.WriteLine(
string.Format("Push Installation Id " + push.InstallationId.ToString()));
var res = await MiscServices.RegisterDevice(Settings.UserID, Settings.AccessToken, push.InstallationId.ToString(), "gcm");
if ((bool)res.data)
{
System.Diagnostics.Debug.WriteLine("Registered InstallationId in Server");
}
else
{
System.Diagnostics.Debug.WriteLine("Cannot register with Server" + " " + res.status.StatusCode);
}
}
catch (Exception e)
{
}
});
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(
string.Format("Error with Azure push registration: {0}", ex.Message));
}
}
protected override void OnUnRegistered(Context context, string registrationId)
{
System.Diagnostics.Debug.WriteLine("Unregistered with Azure push registration");
}
}
}
Even test notifications fail to get delivered at times, but mostly test notifications work fine. We can't really figure out where the issue is occurring, any help is much appreciated.
As you successfully sent messages to Azure NH, and got 201 responses. When you send a notification via Notification Hubs, initially it just gets queued up for NH to do processing to figure out all its targets and then eventually NH sends it to the PNS.
This means that when you are using REST API or any of the client SDK, the successful return of your send call only means that the message has been successfully queued up with Notification Hub.
It doesn’t give an insight into what happened when NH eventually got to send the message to PNS. If your notification is not arriving at the client device, there is a possibility that when NH tried to deliver the message to PNS, there was an error e.g. the payload size exceeded the maximum allowed by the PNS or the credentials configured in NH are invalid etc.
To get an insight into the PNS errors, we have introduced a property called EnableTestSend feature. This property is automatically enabled when you send test messages from the portal or Visual Studio client and therefore allows you to see detailed debugging information.
Or you can try to call via RESTful APIs for troubleshooting:
https://mynamespace.servicebus.windows.net/mynotificationhub/messages?api-version=2013-10&test
Please refer to Azure Notification Hubs - Diagnosis guidelines for more info.

Sendmail ZF2 spaces stripped out of subject

I just created a mailer class for Zend Framework 2. It uses the Sendmail class.
The problem is that I set the subject of the email with multiple words. Before sending I dump the subject and all the spaces are ok. After sending the email I check my gmail and all the spaces are stripped out of the subject.
When I run the script I get "testemail" as the subject.
Below a part of the class I created :
public function addFile($p_sPath, $p_sMimetype, $p_sFilename){
$rFile = fopen($p_sPath,'rb');
$this->_m_oAttachment = new Mimepart(fread($rFile,filesize($p_sPath)));
$this->_m_oAttachment->type = $p_sMimetype;
$this->_m_oAttachment->filename = $p_sFilename;
$this->_m_oAttachment->disposition = 'attachment';
$this->_m_oAttachment->encoding = Mime::ENCODING_BASE64;
}
public function sendEmail()
{
$aParts = (!is_null($this->_m_oAttachment))
? array($this->_m_oBodymessage, $this->_m_oAttachment)
: array($this->_m_oBodymessage);
$this->_m_oBodypart->setParts($aParts);
$this->_m_oMessage->setEncoding('utf-8')
->setBody($this->_m_oBodypart)
->addFrom($this->_fromAddress, $this->_fromName)
->addReplyTo($this->_fromAddress, $this->_fromName)
->setSubject($this->_subject);
// even here the spaces are still intact.
$this->send($this->_m_oMessage);
}
$oMailer = $this->getLocator()->get('Core\Mailer');
$oMailer->setBodyHtml('mail/mail.phtml', array('aData' => $aData));
$oMailer->setSubject('test email');
$oMailer->setRecipient('jacob#myemail.com', 'jacob');
$oMailer->addFile(realpath(dirname(__file__). '/../../../../../'.$sPath.$sSubfolder.'/'.$sFilename), 'application/pdf', $aData['data']['eventID'].'_'.$aDeclaratie['data']['userID'].'.pdf');
$oMailer->sendEmail();
This is fixed with Zend Framework 2 stable
http://framework.zend.com/issues/browse/ZF2-258

Does Ksoap2 require that a web service produce a wsdl?

I have successfully written an Android app which calls an asp.net web service using Ksoap2. I now want to migrate the app to use a PHP web service. I have successfully migrated the web service over to a native PHP web service (and tested it using a PHP client) but I'm having trouble calling it using KSOAP. One thought that struck me was that the native PHP web service was not generated using a wsdl, and is not able to automatically generate a wsdl.
Does ksoap2 require a wsdl to successfully call a web service method?
The asp.net web service is located at http://mycomputer/AlumLocateService/Service.asmx
For the succesful call to asp.net service:
private static final String NAMESPACE = "http://mycomputer/";
private static final String URL = "http://mycomputer/AlumLocateService/Service.asmx";
private static final String METHOD_NAME_3 = "FindCloseDetails";
private static final String SOAP_ACTION_3 = NAMESPACE + METHOD_NAME_3;
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME_3);
PropertyInfo pi = new PropertyInfo();
pi.setName("userid");
pi.setValue(userid);
pi.setType(string.class);
request.addProperty(pi);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION_3, envelope);
//Parse Response
Object myResult = envelope.bodyIn;
SoapObject resultsRequestSOAP = (SoapObject) myResult;
String[] results = getStringArrayResponse(resultsRequestSOAP, null);
return results;
The PHP service is located at http://mycomputer/PHPTest/testserver.php and replicates the methods of the asp.net web service. I had hoped thta all I woudl need to do would be to change the following
private static final String URL = "http://mycomputer/PHPTest/testserver.php";
and remove the line
envelope.dotNet = true;
but when I do that i get "XmlPullParserException: unexpected type (position END_DOCUMENT null...." when the androidHttpTransport.call(SOAP_ACTION_3, envelope) call is made.
One I had changed to using a PHP Zend_Soap_Server I had to change the last part of my Android code to:
Object myResult = envelope.getResponse();
String[] results = null;
if (myResult instanceof Vector)
{
Vector<Object> myVector = (Vector<Object>) myResult;
results = new String[myVector.size()];
for (int i = 0; i< myVector.size();i++){
results[i] = myVector.elementAt(i).toString();
}
}
return results;

Categories